[英]Unexpected snprintf behaviour
我在幾個平台上用c ++注意到(我認為)snprintf非常奇怪的行為。 請考慮以下代碼(導致觀察到的行為的最小工作示例):
#include <stdio.h>
char test1[512];
char test2[512];
char test3[1024];
char test4[1024];
int main()
{
snprintf(test1, sizeof(test1), "test1");
snprintf(test2, sizeof(test2), "test2");
snprintf(test3, sizeof(test3), "%s %s", test1, test2);
return 0;
}
使用--tool = exp-sgcheck運行valgrind時,會報告以下錯誤(對於第3個snprintf語句):
==30302== Invalid read of size 1
==30302== at 0x568E4EB: vfprintf (in /lib64/libc-2.19.so)
==30302== by 0x56B7608: vsnprintf (in /lib64/libc-2.19.so)
==30302== by 0x5695209: snprintf (in /lib64/libc-2.19.so)
==30302== by 0x4006AD: main (1.cc:12)
==30302== Address 0x601460 expected vs actual:
==30302== Expected: global array "test1" of size 1,024 in object with soname "NONE"
==30302== Actual: global array "test2" of size 512 in object with soname "NONE"
==30302== Actual: is 0 after Expected
因此,將test1作為參數傳遞給第一個%s導致在test1數組結束后進行讀取。
此行為導致Windows驅動程序中出現多個頁面錯誤(是的,我知道它是靜態數據...)。 幸運的是代碼是可移植的,當移植到linux valgrind報告錯誤時。
但據我所知,snprintf應該在第6個字節用\\ 0終止test1(它確實如此)。 那么為什么在test1數組結束后讀取第3個snprintf語句呢? 將第3個snprintf語句更改為
snprintf(test3, sizeof(test3), "%.512s %s", test1, test2);
解決了兩個平台上的問題。 將代碼編譯為C代碼(而不是C ++)不會導致錯誤。
更新:在Linux(也可能是Windows)上,如果代碼編譯時包含調試信息並禁用優化(-g -O0表示gcc),則只會發生錯誤。
由於全局對象(如示例中的數組)是0初始化的,因此最后一個snprintf應該永遠不會讀取超出字符串的結尾,而不管先前的sprintfs是否復制了終止0 char。 唯一的解釋是,先前的snprintf復制的內容遠遠超過提交的“test1”到目標test1
,用非0覆蓋所有0(對於隨機內存,不會有0不可能)。
這是不太可能的 - 這樣一個明顯的錯誤早就發現了。 關於驅動程序中的錯誤,我懷疑內存是被完全不相關的“進程”覆蓋的(在一般意義上,可能是另一個驅動程序)。 對於桌面應用程序,我沒有解釋為什么它會失敗。 嘗試使用gcc 4.8.3在Codingground上運行示例運行得很好並在最后添加printf()時打印了預期的字符串。
順便說一句,原始代碼在啟用優化的情況下運行正常並不奇怪:由於沒有可觀察到的影響,編譯器可能只發出一個NOP。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.