亚洲情人网-亚洲情人-亚洲欧洲综合-亚洲欧洲自拍-欧美专区亚洲

數(shù)組越界(數(shù)組越界怎么處理)

  • 生活
  • 2023-04-24 14:33

來自公眾號:技術(shù)讓夢想更偉大

作者:李肖遙

所謂的數(shù)組越界,簡單地講就是指數(shù)組下標(biāo)變量的取值超過了初始定義時(shí)的大小,導(dǎo)致對數(shù)組元素的訪問出現(xiàn)在數(shù)組的范圍之外,這類錯(cuò)誤也是C語言程序中最常見的錯(cuò)誤之一。

在C語言中,數(shù)組必須是靜態(tài)的。換而言之,數(shù)組的大小必須在程序運(yùn)行前就確定下來。由于C語言并不具有類似Java等語言中現(xiàn)有的靜態(tài)分析工具的功能,可以對程序中數(shù)組下標(biāo)取值范圍進(jìn)行嚴(yán)格檢查,一旦發(fā)現(xiàn)數(shù)組上溢或下溢,都會(huì)因拋出異常而終止程序。也就是說,C語言并不檢驗(yàn)數(shù)組邊界,數(shù)組的兩端都有可能越界,從而使其他變量的數(shù)據(jù)甚至程序代碼被破壞。

因此,數(shù)組下標(biāo)的取值范圍只能預(yù)先推斷一個(gè)值來確定數(shù)組的維數(shù),而檢驗(yàn)數(shù)組的邊界是程序員的職責(zé)。

一般情況下,數(shù)組的越界錯(cuò)誤主要包括兩種:數(shù)組下標(biāo)取值越界與指向數(shù)組的指針的指向范圍越界。

數(shù)組下標(biāo)取值越界

數(shù)組下標(biāo)取值越界主要是指訪問數(shù)組的時(shí)候,下標(biāo)的取值不在已定義好的數(shù)組的取值范圍內(nèi),而訪問的是無法獲取的內(nèi)存地址。例如,對于數(shù)組inta[3],它的下標(biāo)取值范圍是[0,2](即a[0]、a[1]與a[2])。如果我們的取值不在這個(gè)范圍內(nèi)(如a[3]),就會(huì)發(fā)生越界錯(cuò)誤。示例代碼如下所示:

inta[3];

inti=0;

for(i=0;i<4;i++)

{

a[i]=i;

}

for(i=0;i<4;i++)

{

printf("a[%d]=%d ",i,a[i]);

}

很顯然,在上面的示例程序中,訪問a[3]是非法的,將會(huì)發(fā)生越界錯(cuò)誤。因此,我們應(yīng)該將上面的代碼修改成如下形式:

inta[3];

inti=0;

for(i=0;i<3;i++)

{

a[i]=i;

}

for(i=0;i<3;i++)

{

printf("a[%d]=%d ",i,a[i]);

}

指向數(shù)組的指針的指向范圍越界

指向數(shù)組的指針的指向范圍越界是指定義數(shù)組時(shí)會(huì)返回一個(gè)指向第一個(gè)變量的頭指針,對這個(gè)指針進(jìn)行加減運(yùn)算可以向前或向后移動(dòng)這個(gè)指針,進(jìn)而訪問數(shù)組中所有的變量。但在移動(dòng)指針時(shí),如果不注意移動(dòng)的次數(shù)和位置,會(huì)使指針指向數(shù)組以外的位置,導(dǎo)致數(shù)組發(fā)生越界錯(cuò)誤。下面的示例代碼就是移動(dòng)指針時(shí)沒有考慮到移動(dòng)的次數(shù)和數(shù)組的范圍,從而使程序訪問了數(shù)組以外的存儲(chǔ)單元。

inti;

int*p;

inta[5];

/*數(shù)組a的頭指針賦值給指針p*/

p=a;

for(i=0;i<10;i++)

{

/*指針p指向的變量*/

*p=i+10;

/*指針p下一個(gè)變量*/

p++;

}

在上面的示例代碼中,for循環(huán)會(huì)使指針p向后移動(dòng)10次,并且每次向指針指向的單元賦值。但是,這里數(shù)組a的下標(biāo)取值范圍是[0,4](即a[0]、a[1]、a[2]、a[3]與a[4])。因此,后5次的操作會(huì)對未知的內(nèi)存區(qū)域賦值,而這種向內(nèi)存未知區(qū)域賦值的操作會(huì)使系統(tǒng)發(fā)生錯(cuò)誤。正確的操作應(yīng)該是指針移動(dòng)的次數(shù)與數(shù)組中的變量個(gè)數(shù)相同,如下面的代碼所示:

inti;

int*p;

inta[5];

/*數(shù)組a的頭指針賦值給指針p*/

p=a;

for(i=0;i<5;i++)

{

/*指針p指向的變量*/

*p=i+10;

/*指針p下一個(gè)變量*/

p++;

}

為了加深大家對數(shù)組越界的了解,下面通過一段完整的數(shù)組越界示例來演示編程中數(shù)組越界將會(huì)導(dǎo)致哪些問題。

1#definePASSWORD"123456"

2intTest(char*str)

3{

4intflag;

5charbuffer[7];

6flag=strcmp(str,PASSWORD);

7strcpy(buffer,str);

8returnflag;

9}

10intmain(void)

11{

12intflag=0;

13charstr[1024];

14while(1)

15{

16printf("請輸入密碼:");

17scanf("%s",str);

18flag=Test(str);

19if(flag)

20{

21printf("密碼錯(cuò)誤! ");

22}

23else

24{

25printf("密碼正確! ");

26}

27}

28return0;

29}

上面的示例代碼模擬了一個(gè)密碼驗(yàn)證的例子,它將用戶輸入的密碼與宏定義中的密碼123456進(jìn)行比較。很顯然,本示例中最大的設(shè)計(jì)漏洞就在于Test()函數(shù)中的strcpy(buffer,str)調(diào)用。

由于程序?qū)⒂脩糨斎氲淖址獠粍?dòng)地復(fù)制到Test()函數(shù)的數(shù)組charbuffer[7]中。因此,當(dāng)用戶的輸入大于7個(gè)字符的緩沖區(qū)尺寸時(shí),就會(huì)發(fā)生數(shù)組越界錯(cuò)誤,這也就是大家所謂的緩沖區(qū)溢出Bufferoverflow漏洞。

但是要注意,如果這個(gè)時(shí)候我們根據(jù)緩沖區(qū)溢出發(fā)生的具體情況填充緩沖區(qū),不但可以避免程序崩潰,還會(huì)影響到程序的執(zhí)行流程,甚至?xí)尦绦蛉?zhí)行緩沖區(qū)里的代碼。示例運(yùn)行結(jié)果為:

1請輸入密碼:12345

2密碼錯(cuò)誤!

3請輸入密碼:123456

4密碼正確!

5請輸入密碼:1234567

6密碼正確!

7請輸入密碼:aaaaaaa

8密碼正確!

9請輸入密碼:0123456

10密碼錯(cuò)誤!

11請輸入密碼:

在示例代碼中,flag變量實(shí)際上是一個(gè)標(biāo)志變量,其值將決定著程序是進(jìn)入密碼錯(cuò)誤的流程(非0)還是“密碼正確”的流程(0)。當(dāng)我們輸入錯(cuò)誤的字符串1234567或者aaaaaaa,程序也都會(huì)輸出“密碼正確”。但在輸入0123456的時(shí)候,程序卻輸出“密碼錯(cuò)誤”,這究竟是為什么呢?

其實(shí),原因很簡單。當(dāng)調(diào)用Test()函數(shù)時(shí),系統(tǒng)將會(huì)給它分配一片連續(xù)的內(nèi)存空間,而變量charbuffer[7]與intflag將會(huì)緊挨著進(jìn)行存儲(chǔ),用戶輸入的字符串將會(huì)被復(fù)制進(jìn)buffer[7]中。如果這個(gè)時(shí)候,我們輸入的字符串?dāng)?shù)量超過6個(gè)(注意,有字符串截?cái)喾菜阋粋€(gè)),那么超出的部分將破壞掉與它緊鄰著的flag變量的內(nèi)容。

當(dāng)輸入的密碼不是宏定義的123456時(shí),字符串比較將返回1或-1。我們都知道,內(nèi)存中的數(shù)據(jù)按照4字節(jié)(DWORD)逆序存儲(chǔ),所以當(dāng)flag為1時(shí),在內(nèi)存中存儲(chǔ)的是0x01000000。如果我們輸入包含7個(gè)字符的錯(cuò)誤密碼,如aaaaaaa,那么字符串截?cái)喾?x00將寫入flag變量,這樣溢出數(shù)組的一個(gè)字節(jié)0x00將恰好把逆序存放的flag變量改為0x00000000。在函數(shù)返回后,一旦main函數(shù)的flag為0,就會(huì)輸出“密碼正確”。這樣,我們就用錯(cuò)誤的密碼得到了正確密碼的運(yùn)行效果。

而對于0123456,因?yàn)樵谶M(jìn)行字符串的大小比較時(shí),它小于123456,flag的值是-1,在內(nèi)存中將按照補(bǔ)碼存放負(fù)數(shù),所以實(shí)際存儲(chǔ)的不是0x01000000而是0xffffffff。那么字符串截?cái)嗪蠓?x00淹沒后,變成0x00ffffff,還是非0,所以沒有進(jìn)入正確分支。

其實(shí),本示例只是用一個(gè)字節(jié)淹沒了鄰接變量,導(dǎo)致程序進(jìn)入密碼正確的處理流程,使設(shè)計(jì)的驗(yàn)證功能失效。

盡量顯式地指定數(shù)組的邊界

在C語言中,為了提高運(yùn)行效率,給程序員更大的空間,為指針操作帶來更多的方便,C語言內(nèi)部本身不檢查數(shù)組下標(biāo)表達(dá)式的取值是否在合法范圍內(nèi),也不檢查指向數(shù)組元素的指針是不是移出了數(shù)組的合法區(qū)域。因此,在編程中使用數(shù)組時(shí)就必須格外謹(jǐn)慎,在對數(shù)組進(jìn)行讀寫操作時(shí)都應(yīng)當(dāng)進(jìn)行相應(yīng)的檢查,以免對數(shù)組的操作超過數(shù)組的邊界,從而發(fā)生緩沖區(qū)溢出漏洞。

要避免程序因數(shù)組越界所發(fā)生的錯(cuò)誤,首先就需要從數(shù)組的邊界定義開始。盡量顯式地指定數(shù)組的邊界,即使它已經(jīng)由初始化值列表隱式指定。示例代碼如下所示:

inta[]={1,2,3,4,5,6,7,8,9,10};

很顯然,對于上面的數(shù)組a[],雖然編譯器可以根據(jù)始化值列表來計(jì)算出數(shù)組的長度。但是,如果我們顯式地指定該數(shù)組的長度,例如:

inta[10]={1,2,3,4,5,6,7,8,9,10};

它不僅使程序具有更好的可讀性,并且大多數(shù)編譯器在數(shù)組長度小于初始化值列表的長度時(shí)還會(huì)發(fā)生相應(yīng)警告。

當(dāng)然,也可以使用宏的形式來顯式指定數(shù)組的邊界(實(shí)際上,這也是最常用的指定***),如下面的代碼所示:

#defineMAX10

inta[MAX]={1,2,3,4,5,6,7,8,9,10};

除此之外,在C99標(biāo)準(zhǔn)中,還允許我們使用單個(gè)指示符為數(shù)組的兩段“分配”空間,如下面的代碼所示:

inta[MAX]={1,2,3,4,5,[MAX-5]=6,7,8,9,10};

在上面的a[MAX]數(shù)組中,如果MAX大于10,數(shù)組中間將用0值元素進(jìn)行填充(填充的個(gè)數(shù)為MAX-10,并從a[5]開始進(jìn)行0值填充);如果MAX小于10,[MAX-5]之前的5個(gè)元素(1,2,3,4,5)中將有幾個(gè)被[MAX-5]之后的5個(gè)元素(6,7,8,9,10)所覆蓋,示例代碼如下所示:

1#defineMAX10

2#defineMAX115

3#defineMAX26

4intmain(void)

5{

6inta[MAX]={1,2,3,4,5,[MAX-5]=6,7,8,9,10};

7intb[MAX1]={1,2,3,4,5,[MAX1-5]=6,7,8,9,10};

8intc[MAX2]={1,2,3,4,5,[MAX2-5]=6,7,8,9,10};

9inti=0;

10intj=0;

11intz=0;

12printf("a[MAX]: ");

13for(i=0;i<MAX;i++)

14{

15printf("a[%d]=%d",i,a[i]);

16}

17printf(" b[MAX1]: ");

18for(j=0;j<MAX1;j++)

19{

20printf("b[%d]=%d",j,b[j]);

21}

22printf(" c[MAX2]: ");

23for(z=0;z<MAX2;z++)

24{

25printf("c[%d]=%d",z,c[z]);

26}

27printf(" ");

28return0;

29}

運(yùn)行結(jié)果為:

1a[MAX]:

2a[0]=1a[1]=2a[2]=3a[3]=4a[4]=5a[5]=6a[6]=7a[7]=8a[8]=9a[9]=10

3b[MAX1]:

4b[0]=1b[1]=2b[2]=3b[3]=4b[4]=5b[5]=0b[6]=0b[7]=0b[8]=0b[9]=0b[10]=6b[11]=7b[12]=8b[13]=9b[14]=10

5c[MAX2]:

6c[0]=1c[1]=6c[2]=7c[3]=8c[4]=9c[5]=10

對數(shù)組做越界檢查,確保索引值位于合法的范圍之內(nèi)

要避免數(shù)組越界,除了上面所闡述的顯式指定數(shù)組的邊界之外,還可以在數(shù)組使用之前進(jìn)行越界檢查,檢查數(shù)組的界限和字符串(也以數(shù)組的方式存放)的結(jié)束,以保證數(shù)組索引值位于合法的范圍之內(nèi)。例如,在寫處理數(shù)組的函數(shù)時(shí),一般應(yīng)該有一個(gè)范圍參數(shù);在處理字符串時(shí)總檢查是否遇到空字符‘

主站蜘蛛池模板: 四虎影免看黄 | 亚洲高清视频在线 | 亚洲视频中文字幕在线 | 免费视频久久 | 在线视频欧美亚洲 | 色婷婷影院在线视频免费播放 | 五月天婷婷丁香 | 2021avtt天堂网手机版 | 亚洲精品福利在线观看 | 亚洲欧美色一区二区三区 | 亚洲视频www| 性色爽爱性色爽爱网站 | 四虎永久免费地址 | 亚洲国产欧美国产综合一区 | 亚洲五月丁香综合视频 | 日韩在线视频不卡 | 亚洲欧美自拍视频 | 欧美国产成人一区二区三区 | 自拍偷拍免费视频 | 日本免费一区二区视频 | 欧美日韩精品一区二区三区四区 | 国产福利精品视频 | 影电影在线观看免费高清完整版 | 免费两性的视频网站 | 综合五月婷婷 | 欧美日韩亚洲一区二区 | 亚洲欧美国产精品专区久久 | 久久久久久久久综合 | 九色国产在视频线精品视频 | 欧美一区二区日韩一区二区 | 亚洲精品国产高清嫩草影院 | 香蕉视频97| 国产精品入口麻豆 | 制服丝袜自拍偷拍 | 一男二女在线观看 | 国色天香社区在线观看免费播放 | 一级国产电影 | a级毛片免费看 | 一区二区在线视频 | 五月天丁香色 | 日韩在线视频在线 |