在 C 語言裡,要建立一個字元陣列的字串,常常會使用 sprintf() 這個函數來做格式化的處理。但是實際上,這個函式卻不是那麼「安全」。怎麼說呢?sprintf() 的整個介面長的樣子的是:
int sprintf ( char * str, const char * format, ... )
也就是在使用前,必須要先建立好一個字元陣列的空間,再用這個函式把內容填入,下面就是簡單的例子:
int tmp = 10; char cstr[20]; sprintf( cstr, "%d * %d = %d", tmp, tmp, tmp * tmp );
在這個例子裡,cstr 最後的值,會是「10 * 10 = 100」,看起來好像很好?但是如果把 tmp 的值改成 10000 的話,cstr 則應該要變成「10000 * 10000 = 100000000」,但是由於這時候的字串所需長度為 26,而要寫入的 cstr的長度只有 20,所以就會造成 buffer overflow 的問題。
像如果是以 Visual C++ 2005 來編譯的話,如果程式裡有用到 sprintf(),他在編譯時就會顯示一個警告訊息:
warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead.
而要怎麼避免 sprintf 的 buffer overflow 的問題呢?除了微軟建議的 sprintf_s() 外,實際上在 C99 裡, 也多了一個 snprinf() 是用來取代現有的 sprintf() 了~他的介面是:
int snprintf(char *str, size_t size, const char * restrict format, ...)
應該可以明顯看得出來,snprinf() 這個函式比 sprinf() 多了一個參數 size;這個參數的用處,就是用來限制最大的寫入資料量,可以用來避免 buffer overflow。以上面的例子來說,本來寫:
int tmp = 10000; char cstr[20]; sprintf( cstr, "%d * %d = %d", tmp, tmp, tmp * tmp );
的話,會產生 buffer overflow 的問題。而如果改成用 snprinf() 的話,就是變成:
int tmp = 10000; char cstr[20]; snprintf( cstr, sizeof( cstr ), "%d * %d = %d", tmp, tmp, tmp * tmp );
這樣一來,snprinf() 在把資料寫到 cstr 時,最多就只會寫入 20 個字元(cstr 的長度),而不會有 buffer overflow 的問題了~
沒有留言:
張貼留言