[英]How to avoid calling fopen() with a buffer that is not null-terminated in C?
我們來看看這個例子:
static FILE *open_file(const char *file_path)
{
char buf[80];
size_t n = snprintf(buf, sizeof (buf), "%s", file_path);
assert(n < sizeof (buf));
return fopen(buf, "r");
}
這里, assert()
是一個接一個。 從snprintf
的聯機幫助頁:
“成功返回后,這些函數返回打印的字符數(不包括用於結束輸出到字符串的空字節)。”
因此,如果它返回80,則字符串將填充緩沖區,並且不會被\\ 0終止。 這將導致問題,因為fopen()
假定它以null結尾。
防止這種情況的最佳方法是什么?
防止這種情況的最佳方法是什么?
很簡單,不要給它一個非空終止字符串。 除了學術問題,您可以控制自己編寫的代碼。 你不必以各種可能的方式防止自己破壞項目,你只需要不要破壞自己。
如果每個人都檢查並仔細檢查代碼中的所有內容,那么性能損失將是不可思議的。 fopen
沒有這樣做的原因。
因此,如果它返回80,則字符串將填充緩沖區,並且不會被
\\0
終止
這是不正確的:無論你為file_path
傳遞什么,字符串都將以null結尾。 顯然,字符串將以sizeof(buf)-1
切斷。
請注意, snprintf
也可以返回80以上的數字。 這意味着您要打印的字符串比您提供的緩沖區長。
防止這種情況的最佳方法是什么?
您已經在這樣做了: assert
不是防止未終止字符串所必需的。 您可以使用返回值來確定是否發生了截斷,並傳遞更大的緩沖區來補償:
// Figure out the size
size_t n = snprintf(NULL, 0, "%s", file_path);
// Allocate the buffer and print into it
char *tmpBuf = malloc(n+1);
snprintf(tmpBuf, n+1, "%s", file_path);
// Prepare the file to return
FILE *res = fopen(tmpBuf, "r");
// Free the temporary buffer
free(tmpBuf);
return res;
這里有幾個問題。
第一個assert()
用於捕獲問題,作為設計器測試的一部分。 它不適用於生產代碼。
其次,如果文件路徑不完整,那么你真的想調用fopen()
嗎?
通常,做的是在預期的字符數中加一。
static FILE *open_file(const char *file_path)
{
char buf[80 + 1] = {0};
size_t n = snprintf(buf, 80, "%s", file_path);
assert(n < sizeof (buf));
return fopen(buf, "r");
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.