了解編譯器所使用的資料模型
使用rsize_t或size_t類型表示所有表示對象長度的整數值
了解整數轉換規則
使用安全的整數庫
對來自不信任來源的整數值實行限制
如果輸入函數無法處理所有可能出現的錯誤就不要用它們轉換字元資料
使用strtol()或相關函數把字元串标記換換為整數
隻使用顯式的有符号或無符号char類型表示數值
驗證所有的整數值位于範圍内
保證枚舉常量映射到唯一的值
使用%操作符時不要假設餘數總是正的
把指針轉換為整數或者把整數轉換為指針時需要小心
當普通的整數位段用于表達式時,不要對它的類型作出假設
隻對無符号操作數使用位操作符
避免在同一個資料上執行位操作和算術運算
在程式員定義的整數類型的格式化i/o中使用intmax_t或者unitmax_t
保證無符号整數運算不産生回繞
保證整型轉換不會丢失或錯誤解釋資料
保證有符号整數運算不會産生溢出
保證除法和求模運算不會導緻除零錯誤
移位的數量不能是負數或大于操作數的位數
把整型表達式比較或指派為一種較大類型之前用這種較大類型對它進行求值
<limits.h>除了提供特定類型的位數資訊之外,還定義了一些宏,可以用于确定任何遵循标準的編譯器所使用的标準整數類型數的整型範圍
e.g. unit_max是unsigned int可以出現的最大值,long_min是long int可以出現的最小值
<sdtint.h>頭檔案在類型中引入了特定的長度限制,可用于避免對特定資料模型的依賴
e.g. int_least32_t是編譯器所支援的最小有符号整數類型,它包含了至少32位
所有編譯器要求提供的類型:
<inttypes.h>聲明了用于操縱最大寬度整數以及把數值字元串轉換為最大寬度整數的函數
代碼:
解決方案:
size_t類型表示sizeof操作符執行結果的無符号整型類型。size_t類型的變量保證具有足夠的精度,能夠表示一個對象的長度。2007
年引入了一種新的類型rsize_t,它被定義為size_t,但是明确用于儲存單個對象的長度,任何表示對象長度的變量,包括作為大小、索引、循環計數
器和長度的整數值,如果有可能,都應該聲明為rsize_t,否則就聲明為size_t
當n > int_max,i超過int_max時,i的值将是從(int_min)開始的負值,p[i]所引用的記憶體位置是在p所引用的記憶體之前,導緻寫入發生在數組邊界之外
解決方案:
轉換可以作為類型轉換的結果顯式或隐式地發生,c99的整數轉換規則定義了c編譯器如何處理轉換,這些規則包括:整型提升、整型轉換秩和尋常算術轉換。
目的是保證轉換結果是相同的值,并且這些值對計算所産生的影響是最小的
整型提升
在執行算術運算的時候,小于int的整數類型将會提升,較小的轉換為int類型,否則轉換為unsigned int類型
假設signed char是用8位值表示,c1 * c2 = 300就無法表示,但是由于整數提升的緣故,c1,c2,c3都轉換為int類型
安全整數庫的一個例子是integerlib,可以免費使用,這個庫的目标是提供一些工具函數的集合,在編寫c程式的時候幫助軟體開發人員避免整數溢出、整數截斷和符号錯誤
所有不信任來源的整數值都應該求值,以确定是否存在可确認的上界和下界
length可接受的範圍定義為[1, max_table_length]
如果輸入函數無法處理所有可能出現的輸入,就不要使用它們把輸入值轉換為整數。比如:scanf()、fscanf()、vscanf()、
vfscanf()這些函數可以處理合法的整數值,但是缺乏對非法值的健壯錯誤處理功能。另一種方法是把字元資料輸入以null字元結尾的位元組字元串形
式,并利用strtol()或者相關函數把它轉換為一個整數值。
一般而言,不要使用scanf對輸入字元串的整數或浮點數進行解析,因為輸入中可能包含實參類型無法表示的數
c99對%操作符的定義提示了下列行為:
17%3=2
17%(-3)=2
-17%3=-2
-17%(-3)=-2
結果與被除數具有相同的符号
解決方案1(使用一個修正的取模内聯函數):
解決方案2(使用size_t):
c99規定(無符号整數将會回繞):涉及無符号操作數的計算不會溢出,因為無法由最終的無符号整數類型表示的結果将會根據這種最終類型可以表示的最大值加1執行求模操作
整數運算:
來自不信任來源的整數值如果按下面方式之一使用,就不允許回繞:
作為數組索引
在任何指針運算中
作為對象的長度或大小
作為數組的上屆(例如循環計數器)
作為記憶體配置設定函數的實參
在安全關鍵代碼中