一些靜態代碼分析工具建議所有的strcat使用應該用strncat替換以達到安全目的?strcat vs strncat - 什麼時候應該使用哪個函數?
在程序中,如果我們清楚地知道目標緩衝區和源緩衝區的大小,是否仍然推薦使用strncat?
另外,鑑於靜態工具的建議,應該使用strcat嗎?
一些靜態代碼分析工具建議所有的strcat使用應該用strncat替換以達到安全目的?strcat vs strncat - 什麼時候應該使用哪個函數?
在程序中,如果我們清楚地知道目標緩衝區和源緩衝區的大小,是否仍然推薦使用strncat?
另外,鑑於靜態工具的建議,應該使用strcat嗎?
如果您完全確定源緩衝區的大小,並且源緩衝區包含終止字符串的NULL字符,那麼當目標緩衝區足夠大時,您可以安全地使用strcat。
我還是建議使用strncat函數,並給它大小的目標緩衝區 - 長度的目標字符串 - 1
注:我編輯了這個,因爲評論指出的是,我以前的答案是可怕的錯誤。
他們不這樣做,所以他們不能被替換。兩者都有不同的數據模型。
strcat
是空 結束的字符串爲您(作爲程序員)保證它有足夠的空間。strncat
是一個序列的char
要麼是終止 在長度你被空終止指示或 如果它是 應該比 長度短 。因此,這些函數的使用僅取決於您可能(或想要)對數據所做的假設。
靜態工具通常很難理解使用函數的情況。我敢打賭,他們中的大多數只是爲每個遇到的strcat發出警告,而不是實際查看傳遞給函數的數據是否是確定性的。如前所述,如果您可以控制輸入數據,那麼這兩項功能都不安全。
雖然注意strncat()稍微慢一些,因爲它必須檢查'\ 0'終止和計數器,並且明確地將其添加到最後。 strcat()另一方面只檢查'\ 0',並通過從第二個字符串複製終止符以及所有數據,將尾部'\ 0'添加到新字符串中。
將兩個字符串連接成一個字符串。
原型
#include <string.h>
char * strcat(char *restrict s1, const char *restrict s2);
char * strncat(char *restrict s1, const char *restrict s2, size_t n);
說明
的strcat()
和strncat()
功能追加空終止 字符串的副本S2到的空終止的端字符串s1,然後添加終止\ 0'。字符串s1必須有足夠的空間來保存 結果。
strncat()函數從s2追加不超過n個字符,然後 添加終止\ 0'。
源和目標字符串不應該重疊,因爲行爲是 未定義。
返回值
The `strcat()` and `strncat()` functions return the pointer s1.
安全考慮
的strcat()
功能很容易,其方式使得惡意用戶通過任意地改變正在運行的程序的功能 濫用緩衝區溢出攻擊。
避免使用strcat()
。相反,使用strncat()
或strlcat()
並確保 沒有更多的字符複製到目標緩衝區,而不是它可以保留的 。
請注意,strncat()
也可能有問題。對於一個字符串來說,截斷可能是一個安全問題。由於截斷的字符串 的長度不會與原始長度相同,因此它可能會引用完全不同的資源,並且截斷的資源的使用可能會導致非常不正確的行爲。例如:
void
foo(const char *arbitrary_string)
{
char onstack[8] = "";
#if defined(BAD)
/*
* This first strcat is bad behavior. Do not use strcat!
*/
(void)strcat(onstack, arbitrary_string); /* BAD! */
#elif defined(BETTER)
/*
* The following two lines demonstrate better use of
* strncat().
*/
(void)strncat(onstack, arbitrary_string,
sizeof(onstack) - strlen(onstack) - 1);
#elif defined(BEST)
/*
* These lines are even more robust due to testing for
* truncation.
*/
if (strlen(arbitrary_string) + 1 >
sizeof(onstack) - strlen(onstack))
err(1, "onstack would be truncated");
(void)strncat(onstack, arbitrary_string,
sizeof(onstack) - strlen(onstack) - 1);
#endif
}
例如
char dest[20] = "Hello";
char *src = ", World!";
char numbers[] = "12345678";
printf("dest before strcat: \"%s\"\n", dest); // "Hello"
strcat(dest, src);
printf("dest after strcat: \"%s\"\n", dest); // "Hello, World!"
strncat(dest, numbers, 3); // strcat first 3 chars of numbers
printf("dest after strncat: \"%s\"\n", dest); // "Hello, World!123"
1。我會強調,在某些系統(例如BSD)中,如果使用'size-generic'字符串操作函數(strcat,strcpy等),編譯器會發出警告 – dave
我認爲你的意思是「......給它的大小的目標緩衝區_minus它已經包含的字符串的大小_「 – Nemo
這個答案是非常危險的錯誤。 @Nemo更接近了,但我認爲仍然是一個。 [Pankaj的回答](http://stackoverflow.com/a/6502352/228539)顯示準確,並且非常詳細。它必須是'目標緩衝區的大小 - 目標字符串的長度 - 1'以適當地避免緩衝區溢出。雖然在設計這個函數時看起來確實是一個愚蠢的選擇,因爲它在開始複製之前必須固有地尋找空終止符,並且可以計算一直沿途的長度,所以我們不必這樣做兩次。 – altendky