在C語言中,許多標準庫函數(如?strcpy
、scanf
、gets
?等)由于缺乏邊界檢查,容易導致 ?緩沖區溢出(Buffer Overflow)?、內存越界訪問? 等安全問題。為了解決這些問題,C11標準引入了 ?安全函數(Safe Functions)?,同時一些編譯器(如MSVC、GCC)也提供了替代方案(如?_s
?后綴函數或?strlcpy
)。
例如,當我們將一個字符串要賦值到另一個數組中時,我們一般會使用C語言自帶的strcpy函數,但是針對該函數的底層實現,僅僅只是傻瓜式的將源地址的數據存儲到目的地址,不會注意緩沖區是否溢出,如果目的地址空間不夠,那么相鄰的地址的值會被改變,然后讀取的數據不對,嚴重的可能會造成程序崩潰。
#include <stdio.h>
#include <string.h>int main()
{char *str = "This is a test string";char dest[10],dest2[10];printf("dest addr = %p\n", dest);printf("dest2 addr = %p\n", dest2);strcpy(dest2, str); // 溢出導致未定義行為printf("dest str: %s\n", dest);printf("dest2 str: %s\n", dest2);return 0;
}
因此,為了規避上述問題,C11標準定義了 ?邊界檢查接口(Bounds-checking interfaces)?,函數以?_s
?后綴標識,需傳遞目標緩沖區大小。例如采用下面的安全函數進行賦值,那么只會賦值失敗,不會有什么其他的危險
#include <stdio.h>
#include <string.h>int main()
{char *str = "This is a test string";char dest[10];printf("dest addr = %p\n", dest);if (strcpy_s(dest, sizeof(dest), str) == 0) {printf("Copied: %s\n", dest);} else {printf("Copy failed: buffer too small\n");}return 0;
}
除開上面的strcpy有安全函數外,還有其他函數也具有邊界安全函數
?函數? | ?作用? | ?示例? |
---|---|---|
strcat_s | 安全拼接字符串 | strcat_s(dest, sizeof(dest), src) |
scanf_s | 安全格式化輸入 | scanf_s("%9s", buf, sizeof(buf)) |
memcpy_s | 安全內存復制 | memcpy_s(dest, sizeof(dest), src, n) |
總體來說,安全函數的核心?:通過顯式傳遞緩沖區大小防止溢出。而這更重要的一點就是始終檢查邊界、驗證輸入、啟用編譯器警告,需要讓代碼做到0警告,以后調用一些C語言函數時,可以先了解一下是否有安全函數,如果有就可以直接用,雖然這是一個小問題,但是會無意間增加代碼的魯棒性。