您的位置:首頁>正文

一道C語言安全編碼題目

1、前言

最近在網上看到一道C語言題目, 用C語言實現一個函數, 給定一個int類型的整數, 函數輸出逆序的整數, 例如輸入123, 則輸出字串"321",, 輸入-123, 則輸出字串"-321"。 題目要求, 不使用標準庫, 不得分配記憶體。 當時覺得蠻簡單的, 這不就是類似字串逆轉嘛, 自己嘗試做了一下, 測試發現, 還是有很多地方考慮不周全。 今天在此整理一下基礎知識, 作為一名安全開發人員, 時刻需要注意代碼的安全, 防止有任何漏洞。 題目給出的函數如下:

#include const char * parseInt(int data) { return "321"; } int main { printf("%s ", parseInt(123)); return 0; }

2、思考過程

寫代碼最怕的就是沒有想好, 一上來就寫, 在寫的過程中不斷的測試修改,

這樣很浪費時間。 因此需要先好好想一下, 這個題目到底考些什麼呢?

(1)int類型的整數分為正數、0、負數, 如何處理這些邊界值

(2)整數與字串之間的轉換, 如何將一個整數轉換為一個字元

(3)如何返回一個const char * 類型的字串

(4)當輸入的整數超過int的範圍如何處理

3、編碼過程

開始寫代碼的思路如下:定義一個char類型的陣列, 用於保存結果。 使用對10取餘和除法操作依次獲取每一位元的數位, 然後根據ASSIC碼轉換為字元。 將字元拼接起來, 返回字串陣列結果。 編碼實現如下:

const char * parseInt(int data) { char str[16] = {0}; int i = 0; if (data

當初沒有考慮那麼多, 編譯發現出現如下錯誤:

一看編譯錯誤, 才意識到自己掉入坑中。 題目要求返回一個字串, 而且不用分配記憶體。 當時就想直接定義一個字元陣列進行返回,

而定義的str屬於函數區域變數。

一個函數的區域變數都是存在stack中的, 當這個函式呼叫過程結束時, 這個區域變數都是要釋放掉的, 所以就會產生這樣的warning, 這個是和變數的life time相關的, 所以解決方法有:

1.將char result[16]改為static型

2.使用malloc向heap申請, 這些是需要caller用free去釋放的

於是使用static 類型字串, 代碼改進如下:

1 const char * parseInt(int data) 2 { 3 static char str[16] = {0}; 4 int i = 0; 5 6 if (data

int main

{

printf("%s ", parseInt(123));

printf("%s ", parseInt(12345678));

printf("%s ", parseInt(-89790));

return 0;

}

測試結果如下:

改為static之後, 編譯成功, 看輸出的結果上看, 前面兩個輸出是正確的, 而第三個輸出的結果是錯誤的。 尼瑪, 再次掉入坑中, 對static變數的應用不精通啊。 為什麼每次到看到結果後才想起來?

雖然在函數中定義了static區域變數, 使得變數的變為靜態stack存儲區域, 生命週期從函數中變成了這個程式的範圍。 但是static區域變數在函數第一次調用的時候會初始化,

後面調用就不會了, 直接使用了。 因此導致了剛才的結果輸出不對, 複用了上次遺留的結果。

static靜態區域變數屬於靜態存儲方式, 它具有以下特點:

(1)靜態區域變數在函數內定義 它的生存期為整個來源程式, 但是其作用域仍與自動變數相同, 只能在定義該變數的函數內使用該變數。 退出該函數後, 儘管該變數還繼續存在, 但不能使用它。

(2)允許對構造類靜態局部量賦初值 例如陣列, 若未賦以初值, 則由系統自動賦以0值。

(3)對基本類型的靜態區域變數若在說明時未賦以初值, 則系統自動賦予0值。 而對自動變數不賦初值, 則其值是不定的。 根據靜態區域變數的特點, 可以 看出它是一種生存期為整個來源程式的量。

雖然離開定義它的函數後不能使用, 但如再次調用定義它的函數時, 它又可繼續使用, 而且保存了前次被調用後留下的 值。 因此, 當多次調用一個函數且要求在調用之間保留某些變數的值時, 可考慮採用靜態區域變數。 雖然用全域變數也可以達到上述目的, 但全域變數有時會造成 意外的副作用, 因此仍以採用局部靜態變數為宜。

第一次調用函數, static變數, 初始化。 第二次, 及以後, 調用函數, static變數, 不會初始化。

繼續改進代碼, 在函數中將static變數每次使用for迴圈進行初始化, 改進代碼如下:

1 #include 2 3 const char * parseInt(int data) 4 { 5 static char str[16] = {0}; 6 int i = 0; 7 8 int t = 0; 9 for (; t

這次輸出結果如下:

終於得到了正確答案, 看似很簡單的題目, 折騰的這麼久, 才搞出來。 擴展一下, 大家看看如下這個輸出什麼呢:

printf("%s, %s, %s ", parseInt(98989),parseInt(-4567), parseInt(123456));

這個結果是什麼呢?為什麼會這樣呢?

printf("%s ", parseInt(0x8FFFFFFF));
printf("%s ", parseInt(0xFFFFFFFF));

這個結果是什麼呢?為什麼會這樣呢?

int 類型4個位元組, 32位元組成。 int的最高位元作為符號位元, 需要特殊處理。

同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示