支持 macOS、Windows (MSVC) 和 Linux,我該如何執行以下操作?
char *s;
func(&s, "foo");
if (<condition>) func(&s, "bar%s", "can")
/* want "foobarcan", and I don't know `strlen(s)` AoT */
我已經嘗試過asprintf(能夠找到一個 MSVC 實作),但在這種作業流程上似乎效果不佳。fopencookie并且funopen看起來很方便,但在 MSVC 上不可用。
也許有一些干凈的方法realloc可以創建以char*C 結尾的 NUL?
uj5u.com熱心網友回復:
正如評論中所指出的,即使被截斷,也(v)snprintf總是回傳將被寫入的位元組數(不包括空終止位元組)。這具有為函式提供size引數的效果,0回傳要格式化的字串的長度。
使用這個值,加上我們現有字串的字串長度(如果適用),再加一,我們(重新)分配適當的記憶體量。
要連接,只需在正確的偏移量處列印格式化的字串。
一個例子,沒有錯誤檢查。
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *dstr(char **unto, const char *fmt, ...) {
va_list args;
size_t base_length = unto && *unto ? strlen(*unto) : 0;
va_start(args, fmt);
/* check length for failure */
int length = vsnprintf(NULL, 0, fmt, args);
va_end(args);
/* check result for failure */
char *result = realloc(unto ? *unto : NULL, base_length length 1);
va_start(args, fmt);
/* check for failure*/
vsprintf(result base_length, fmt, args);
va_end(args);
if (unto)
*unto = result;
return result;
}
int main(void) {
char *s = dstr(NULL, "foo");
dstr(&s, "bar%s%d", "can", 7);
printf("[[%s]]\n", s);
free(s);
}
stdout:
[[foobarcan7]]
這里需要注意的是你不能寫:
char *s;
dstr(&s, "foo");
s必須初始化為NULL,或者該函式必須直接用作初始化器,第一個引數設定為NULL。
That, and the second argument is always treated as a format string. Use other means of preallocating the first string if it contains unsanitary data.
Example exploit:
/* exploit */
char buf[128];
fgets(buf, sizeof buf, stdin);
char *str = dstr(NULL, buf);
puts(str);
free(str);
stdin:
%d%s%s%s%s%d%p%dpapdpasd%d%.2f%p%d
Result: Undefined Behavior
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/448222.html
下一篇:需要澄清遞回函式方法論
