如果使用sprintf()或vsprintf(),則需要首先分配緩衝區,並且需要確保緩衝區足夠大以包含sprintf寫入的內容。否則,sprintf會高興地覆蓋超出緩衝區末端的內存。
char* x = malloc(5 * sizeof(char));
sprintf(x,"%s%s%s", "12", "34", "56"); // writes "123456" +null but overruns the buffer
...寫入「6」和終止null
超出分配給x
的空間的端部,或者破壞某些其他變量,或引起段故障。
如果幸運的話,它會在分配的塊之間的內存上踐踏,並且不會造成傷害 - 這一次。這會導致間歇性的錯誤 - 最難診斷的錯誤。使用類似ElectricFence這樣的工具會很好,它會導致超限失效。
提供超長輸入的非惡意用戶可能會導致程序以意外的方式運行。惡意用戶可以利用這種方式將自己的可執行代碼加入系統。
對此的一個警告是使用snprintf()
,它將字符串截斷爲您提供的最大長度。
char *x = malloc(5 * sizeof(char));
int size = snprintf(x, 5, "%s%s%s", "12", "34", "56"); // writes "1234" + null
返回值size
是長度本來書面如果空間是可利用的 - 不包括終止空。
在這種情況下,如果size
大於或等於5,那麼你知道,截斷髮生 - 如果你不想截斷,你可以分配一個新的字符串,然後再次嘗試snprintf()
。
char *x = malloc(BUF_LEN * sizeof(char));
int size = snprintf(x, 5, "%s%s%s", "12", "34", "56");
if(size >= BUF_LEN) {
realloc(&x,(size + 1) * sizeof(char));
snprintf(x, 5, "%s%s%s", "12", "34", "56");
}
(這是一個非常天真的算法,但它說明了這一點)
asprintf()
做這一步爲您服務 - 計算字符串的長度,分配的內存量,並寫入字符串進去。
char *x;
int size = asprintf(&x, "%s%s%s", "12", "34", "56");
在所有情況下,一旦你與x
完成,你需要釋放它,或者你內存泄漏:
free(x);
asprintf()
一個隱含的malloc()
,所以你必須檢查它的工作,就像使用malloc()
或任何其他系統調用一樣。
if(size == -1) {
/* deal with error in some way */
}
注意asprintf()
是GNU和BSD擴展的一部分到libc - 你不能肯定它會在每一個C環境中使用。 sprintf()
和snprintf()
是POSIX和C99標準的一部分。
'asprintf()'和'vasprintf()'是GNU擴展。添加了GNU標籤。 – alk
嗯,我不知道提問者是否在這裏練習:http://exploit-exercises.com/nebula/level02? – jordanpg
關於此主題的非常好的博客文章可以在這裏找到:[內存管理在C和自動](http://insanecoding.blogspot.de/2014/06/memory-management-in-c-和 - auto.html)...順便說一句。完整的博客是值得的 – antibus