- C和C++安全編碼(原書第2版)
- (美)Robert C.Seacord
- 975字
- 2020-10-30 17:56:39
2.2.3 空字符結尾錯誤
另一個常見的問題是字符串沒有正確地以空字符結尾。一個字符串正確地以空字符結尾,是指在數組最后一個元素處或在它之前存在一個空終結符。如果一個字符串沒有以空字符結尾,程序可能會被欺騙,導致在數組邊界之外讀取或寫入數據。
字符串必須在數組的最后一個元素的地址處或在它之前包含一個空終止字符,才可以安全地作為標準字符串處理函數如strcpy()函數或strlen()函數的參數被傳遞。空終止字符之所以是必要的,是因為前面這些函數以及其他由C標準定義的字符串處理函數,都依賴于它的存在來標記字符串的結尾。同樣,如果程序對一個字符數組迭代循環的終止條件取決于為字符串分配的內存內是否存在一個空終止字符,字符串也必須以空字符結尾。
1 size_t i; 2 char ntbs[16]; 3 /* ... */ 4 for (i = 0; i < sizeof(ntbs); ++i) { 5 if (ntbs[i] == '\0') break; 6 /* ... */ 7 }
下面的程序在微軟Visual C++2010中能通過編譯,但在警告級別/W3下會對使用strncpy()和strcpy()發出警告。如果_FORTIFY_SOURCE宏被定義為一個非零值,它在Linux下還會(在運行時)由GCC診斷。
1 int main(void) { 2 char a[16]; 3 char b[16]; 4 char c[16]; 5 strncpy(a, "0123456789abcdef", sizeof(a)); 6 strncpy(b, "0123456789abcdef", sizeof(b)); 7 strcpy(c, a); 8 /* ... */ 9 }
在這個程序中,三個字符數組(a[]、b[]和c[])被聲明為16個字節。雖然strncpy()到a僅限于寫sizeof(a)(16個字節),但由于strncpy()函數的歷史和標準的行為,導致結果字符串不是以空字符結尾的。
根據C標準,strncpy()函數從源數組復制不超過n個字符(空字符后的字符不會被復制)到目標數組。因此,如本例所示,如果源數組中的前n個字符中不存在空字符,那么其結果字符串將不會是以空字符結尾的。
strncpy()到b也有類似的結果。這取決于編譯器如何分配存儲空間,a[]后的存儲空間可能碰巧存在一個空字符,但是這是編譯器未指定的,并在本例中是不太可能的,尤其是存儲空間是緊密堆積的時候。其結果是strcpy()到c可能寫得遠遠超出了數組界限,因為a[]中存儲的字符串不是正確地以空字符結尾的。
《C安全編碼標準》[Seacord 2008]包括“STR 32-C.按要求提供空字節結尾的字符串”。請注意,該規則并不排除使用字符數組。例如,即使在調用strncpy()之后,存儲在ntbs字符數組中的字符串可能不是正確地以空字符結尾的,下面的程序片段也沒有什么錯。
1 char ntbs[NTBS_SIZE]; 2 3 strncpy(ntbs, source, sizeof(ntbs)-1); 4 ntbs[sizeof(ntbs)-1] = '\0';
與本章中描述的其他字符串操作錯誤一樣,空字符結尾錯誤也很難檢測,它們會潛伏在部署好的代碼中,直至遇到一組特別的輸入而導致發生錯誤。編寫代碼不能依賴于編譯器如何分配內存,因為這在編譯器的下個版本中很可能發生改變。
- PHP動態網站程序設計
- INSTANT Mock Testing with PowerMock
- Web程序設計及應用
- JavaScript全程指南
- Practical Data Science Cookbook(Second Edition)
- Internet of Things with Intel Galileo
- Android 應用案例開發大全(第3版)
- ADI DSP應用技術集錦
- Python:Master the Art of Design Patterns
- Java Web開發就該這樣學
- ASP.NET程序開發范例寶典
- Building Slack Bots
- Java從入門到精通(視頻實戰版)
- 你必須知道的.NET(第2版)
- 系統分析師UML用例實戰