最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C/C++使用過程中的溢出問題詳解

 更新時間:2024年01月08日 11:58:40   作者:嵌入式學(xué)習(xí)菌  
在C/C++程序里有一類非常典型的問題,那就是:溢出問題,現(xiàn)在分別來分析一下常見的數(shù)組溢出,整數(shù)溢出,緩沖區(qū)溢出,棧溢出和指針溢出等,需要的朋友可以參考下

內(nèi)容:在C/C++程序里有一類非常典型的問題,那就是:溢出問題?,F(xiàn)在分別來分析一下常見的數(shù)組溢出,整數(shù)溢出,緩沖區(qū)溢出,棧溢出和指針溢出等。

1、數(shù)組溢出

在C語言中,數(shù)組的元素下標(biāo)是從0開始計算的,所以,對于n個元素的數(shù)組a[n], 遍歷它的時候是a[0],a[1],...,a[n-1],如果遍歷到a[n],數(shù)組就溢出了。 

void print_array(int a[], int n)
{
    for (int i = 0; i < n; i++) 
    {
        a[i] = a[i+1];//當(dāng)i = n-1時,就發(fā)生了數(shù)組越界
        printf(“%d\n”, a[i]);
    }
}

上面的循環(huán)判斷應(yīng)該改為:
for (int i = 0; i < n-1; i++)

2、整數(shù)溢出

整數(shù)的溢出分為下溢出和上溢出。比如,對于有符號的char(signed char)類型來說,它能表示的范圍為:[-128,127]之間;而對于無符號的char(unsigned char)來說, 它能表示的范圍為:[0,255]。

那么,對于下面的代碼:

signed char c1 = 127;
c1 = c1+1;//發(fā)生上溢出,c1的值將變?yōu)?128
signed char c2 = -128;
c2 = c2-1;//發(fā)生下溢出,c2的值將變?yōu)?27
unsigned char c3 = 255;
c3 = c3+1;//發(fā)生上溢出,c3的值將變?yōu)?
unsigned char c4 = 0;
c4 = c4-1;//發(fā)生下溢出,c4的值將變?yōu)?55

從上面的例子可以看出,當(dāng)一個整數(shù)向上溢出,將會變?yōu)樽钚≈担蛳乱绯?,將會變?yōu)樽畲笾怠?/p>

來看下面的溢出代碼,該代碼負(fù)責(zé)提供一個小寫字母轉(zhuǎn)換表,但存在一個整數(shù)溢出問題:

void BuildToLowerTable( void ) /* ASCII版本*/
{
    unsigned char ch;
    /* 首先將每個字符置為它自己 */
    /*ch為unsigned char,無符號數(shù),當(dāng)ch值為UCHAR_MAX, ch++將會發(fā)生向上溢出,變?yōu)?,導(dǎo)致循環(huán)無法退出。*/
    for (ch=0; ch <= UCHAR_MAX;ch++)
        chToLower[ch] = ch;
    /* 將大寫字母改為小寫字母 */
    for( ch = ‘A'; ch <= ‘Z'; ch++ )
        chToLower[ch] = ch +'a' – ‘A';
}

該代碼負(fù)責(zé)在內(nèi)存中查找指定的字符ch,但也存在一個溢出問題

void * memchr( void *pv, unsigned char ch, size_t size )
{
    unsigned char *pch = (unsigned char *) pv;
    /*當(dāng)size的值為0的時候,由于size是無符號整數(shù),因此會發(fā)生下溢出,變?yōu)橐粋€最大的整數(shù) 循環(huán)也將無法退出*/ 
    while( -- size >=0 )
    {
        if( *pch == ch )
            return (pch );
        pch++;
    }
    return( NULL );
}

3、緩沖區(qū)溢出

緩沖區(qū)溢出一般是調(diào)用了一些不安全的字符串操作函數(shù)比如:strcpy,strcat等(這些字符串操作函數(shù)在拷貝或者修改目標(biāo)位置的時候,并不判斷長度是否會超過目標(biāo)緩存),或者設(shè)置參數(shù)超過了目標(biāo)緩存能容納的大小而造成的溢出問題。

void func1(char* s)
{
    char buf[10];
    /*此時,buf只有10個字節(jié),如果傳入的s超過10個字節(jié),就會造成溢出*/
    strcpy(buf, s);
}
void func2(void)
{
    printf("Hacked by me.\n");
    exit(0);
}
int main(int argc, char* argv[])
{
    char badCode[] = "aaaabbbb2222cccc4444ffff";
    DWORD* pEIP = (DWORD*)&badCode[16];
    *pEIP = (DWORD)func2;
    /*badCode字符串超過了10個字節(jié),傳遞給func1會造成棧上緩沖區(qū)溢出
    而且,由于badCode經(jīng)過精心構(gòu)造,在溢出的時候,根據(jù)函數(shù)的調(diào)用約定規(guī)則,會覆蓋棧上的返回地址,
    指向了func2。所以,在func1退出的時候,會直接調(diào)用func2
    */
    func1(badCode);
    return 0;
}

4、棧溢出

無論是內(nèi)核棧,還是應(yīng)用層的棧,都是有一定大小限制的。如果在棧上分配的空間大于了這個限制,就會造成棧大小溢出,破壞棧上的數(shù)據(jù)。比如局部變量過多,或者遞歸調(diào)度嵌套太深都會造成棧溢出。比如:

int init_module(void)
{
    char buf[10000]; //buf[]分配在棧上,但10000的空間超過了棧的默認(rèn)大小8KB。
    //所以發(fā)生溢出
    memset(buf,0,10000);
    printk("kernel stack.\n");
    return 0;
}
void cleanup_module(void)
{ 
    printk("goodbye.\n");
}
MODULE_LICENSE("GPL");
//應(yīng)用棧的大小對少?內(nèi)核棧的大小多少?什么時候容易棧溢出?

5、指針溢出

一塊長度為size大小的內(nèi)存buffer,buffer的首地址為p,那么buffer最后一個字節(jié)的地址:
p+size-1,而不是p+size。如果寫成了p+size,就會造成溢出,比如下面的代碼:

void* memchr( void *pv, unsigned char ch, size_t size )
{
    unsigned char *pch = ( unsigned char * )pv;
    unsigned char *pchEnd = pch + size;
    while( pch < pchEnd )
    {
        if( *pch == ch )
            return ( pch );
        pch ++ ;
    }
    return( NULL );
}

上面的代碼用于查找內(nèi)存中特定的字符位置。對于其中的while()循環(huán),平時執(zhí)行似乎都沒有任何問題。但是,考慮一種特別情況,即pv所指的內(nèi)存位置為末尾若干字節(jié),那么因為pchEnd = pch+size,所以pchEnd指向最后一個字符的下一個字節(jié),將會超出內(nèi)存的范圍,即pchEnd所指的位置已經(jīng)不存在。
知道了問題所在,那么可以將內(nèi)存的結(jié)尾計算方式改為: 

pchEnd = pv + size – 1; 
while ( pch <= pchEnd ) 
{
        if( *pch == ch )
            return ( pch );
        pch ++ ;
}

pchEnd指向了最后一個字節(jié)。但是,檢查循環(huán)內(nèi)部的執(zhí)行情況可知,由于pch每增加到pchEnd+1時,都會發(fā)生上溢。因此,循環(huán)將無法退出。 于是,可以將程序修改為下面的代碼。將用size變量來控制循環(huán)的退出。這樣就不會存在任何問題了。

void *memchr( void *pv, unsigned char ch, size_t size )
{
    unsigned char *pch = ( unsigned char * )pv;
    while( size -- > 0 )
    {
        if( *pch == ch )
            return( pch );
        pch ++;
    }
    return( NULL );
}

大家知道,--size的效率一般比size--的效率高。那么是否可以將循環(huán)的判斷條件改為下面的語句呢? 
while( --size >= 0 ) 
…… 

實際上這是不行的。因為當(dāng)size=0時,由于size是無符號數(shù),那么它將發(fā)生下溢,變成了size所能表示的最大正數(shù),循環(huán)也將無法退出。 

6、字符串溢出

我們已經(jīng)知道,字符串是'\0'結(jié)尾的。如果字符串結(jié)尾忘記帶上'\0',那么就溢出了。注意,strlen(p)計算的是字符串中有效的字符數(shù)(不含’\0’)??疾煜旅婵截愖址拇a,看看有什么問題沒呢?

char *str = “Hello, how are you!”;

char *strbak = (char *)malloc(strlen(str));

if (NULL == strbak)

{

//處理內(nèi)存分配失敗,返回錯誤

}

strcpy(strbak, str);

顯然,由于strlen()計算的不是str的實際長度(即不包含’\0’字符的計算),所以strbak沒有結(jié)束符’\0’,而在C語言中,’\0’是字符串的結(jié)束標(biāo)志,所以是必須加上的,否則會造成字符串的溢出。所以上面的代碼應(yīng)該是:

char *str = “Hello, how are you!”;

char *strbak = (char *)malloc(strlen(str)+1);

if (NULL == strbak)

{

    //內(nèi)存分配失敗,返回錯誤

}

strcpy(strbak, str);

到此這篇關(guān)于C/C++使用過程中的溢出問題詳解的文章就介紹到這了,更多相關(guān)C/C++溢出問題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++ std::list的merge()使用方式與分析

    C++ std::list的merge()使用方式與分析

    這篇文章主要介紹了C++ std::list的merge()使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • 算法之排列算法與組合算法詳解

    算法之排列算法與組合算法詳解

    這篇文章主要介紹了算法之排列算法與組合算法詳解,本文以字典序法、遞歸法為例講解了排列算法、全組合算法等,需要的朋友可以參考下
    2014-08-08
  • C語言求2的n次方多種方法總結(jié)

    C語言求2的n次方多種方法總結(jié)

    這篇文章主要給大家介紹了關(guān)于C語言求2的n次方多種方法的相關(guān)資料,求2的N次冪是一個常用的功能,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-10-10
  • 詳解c++ atomic原子編程中的Memory Order

    詳解c++ atomic原子編程中的Memory Order

    在多核編程中,我們使用內(nèi)核對象【如:事件對象(Event)、互斥量對象(Mutex,或互斥體對象)、信號量對象(Semaphore)等】來避免多個線程修改同一個數(shù)據(jù)時產(chǎn)生的競爭條件。本文將詳細(xì)介紹c++ atomic原子編程中的Memory Order。
    2021-06-06
  • C++數(shù)據(jù)結(jié)構(gòu)之哈希算法詳解

    C++數(shù)據(jù)結(jié)構(gòu)之哈希算法詳解

    這篇文章主要為大家詳細(xì)介紹了C++數(shù)據(jù)結(jié)構(gòu)中哈希算法的相關(guān)資料,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,希望對大家有所幫助
    2022-12-12
  • C++中md5 算法實現(xiàn)代碼

    C++中md5 算法實現(xiàn)代碼

    在網(wǎng)上找了份c++ MD5的代碼,就簡單保存一下,需要的朋友可以參考下
    2017-07-07
  • 詳解C++中的內(nèi)聯(lián)函數(shù)和函數(shù)重載

    詳解C++中的內(nèi)聯(lián)函數(shù)和函數(shù)重載

    這篇文章主要介紹了詳解C++中的內(nèi)聯(lián)函數(shù)和函數(shù)重載,是C++入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09
  • 詳解VS2019+OpenCV-4-1-0+OpenCV-contrib-4-1-0

    詳解VS2019+OpenCV-4-1-0+OpenCV-contrib-4-1-0

    這篇文章主要介紹了詳解VS2019+OpenCV-4-1-0+OpenCV-contrib-4-1-0,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • 詳解C++泛型裝飾器

    詳解C++泛型裝飾器

    這篇文章主要為大家介紹了C++的泛型裝飾器,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2021-11-11
  • C++ string字符串的使用和簡單模擬實現(xiàn)

    C++ string字符串的使用和簡單模擬實現(xiàn)

    C語言中,字符串是以'\0'結(jié)尾的一些字符的集合,為了操作方便,C標(biāo)準(zhǔn)庫中提供了一些str系列的庫函數(shù),但是這些庫函數(shù)和字符串是分離的,本文給大家介紹了C++ string字符串的使用和簡單模擬實現(xiàn),感興趣的朋友可以參考下
    2024-06-06

最新評論

隆林| 吉木萨尔县| 岳西县| 五常市| 长顺县| 铅山县| 桑植县| 资讯 | 宕昌县| 定南县| 昭平县| 石嘴山市| 若羌县| 临汾市| 双江| 扎兰屯市| 霍州市| 全椒县| 宕昌县| 湖北省| 建始县| 沈丘县| 荥经县| 邵武市| 尼勒克县| 屯门区| 于都县| 宜宾市| 锡林郭勒盟| 许昌市| 北安市| 安宁市| 西青区| 云梦县| 时尚| 抚远县| 厦门市| 新疆| 于都县| 南宁市| 姜堰市|