tl;dr可以asprintf
在不调用临时指针的情况下天真地用于连接吗?
asprintf
GNU 引入并在其他几个 clib 实现中采用的函数是使用类似方案的 c 中任意连接的诱人解决方案
int i=0;
char *str = strdup(argv[i]);
while (argv[++i]) {
asprintf(&str,"%s %s",argv[i],str); // <=== This line
}
asprintf(&str,"%s\n",str);
当包裹在一个主要的和必要的包含中时,这对我来说运行良好。
但...
它是否到处泄漏内存?Valgrind 说它在我的盒子上。这是一个错误吗?
我面前的手册页说
asprintf() 和 vasprintf() 函数将 *ret 设置为指向足够大以保存格式化字符串的缓冲区的指针。这个指针应该被传递给 free(3) 以在不再需要时释放分配的存储空间。如果无法分配足够的空间, asprintf() 和 vasprintf() 将返回 -1 并将 ret 设置为 NULL 指针。
在没有“set *ret
to be a pointer to a new buffer [...]”这句话的情况下,我很想假设该函数realloc
按原样getline
使用。
可能是什么问题?
使用具体的签名int asprintf(char **ret, const char *format, ...);
。
asprintf
跑得太快realloc
了。想象一下,我们在如此远的地方实现该函数,以至于我们可以
realloc(*ret)
在它取消引用为原始缓冲区别名的可变参数之一之前运行。该缓冲区已被释放,这在技术上是未定义的行为。这将代表一个错误。asprintf
在读取缓冲区之前写入缓冲区。在上面的代码中,我们可以将函数的内容复制argv[1]
到*ret
它之前的每个参数va_arg
上。str
我引用的联机帮助页似乎并没有排除这种情况。asprintf
不free *ret
直接或通过使用realloc
. 这将避免问题编号 (1),但如果按上述方式使用,则会泄漏内存。同样,该手册页似乎并未排除它。
解决方法
通过将单个调用替换asprintf
为
{
char *newStr = NULL;
asprintf(newStr,"%s %s",argv[i],str);
free(str);
str = newStr;
}
但这很笨拙。
共识实现是否保证第一个代码示例是安全正确的?