6

tl;dr可以asprintf在不调用临时指针的情况下天真地用于连接吗?


asprintfGNU 引入并在其他几个 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 *retto be a pointer to a new buffer [...]”这句话的情况下,我很想假设该函数realloc按原样getline使用。

可能是什么问题?

使用具体的签名int asprintf(char **ret, const char *format, ...);

  1. asprintf跑得太快realloc了。

    想象一下,我们在如此远的地方实现该函数,以至于我们可以realloc(*ret)在它取消引用为原始缓冲区别名的可变参数之一之前运行。该缓冲区已被释放,这在技术上是未定义的行为。这将代表一个错误。

  2. asprintf在读取缓冲区之前写入缓冲区。在上面的代码中,我们可以将函数的内容复制argv[1]*ret它之前的每个参数va_arg上。str我引用的联机帮助页似乎并没有排除这种情况。

  3. asprintffree *ret直接或通过使用realloc. 这将避免问题编号 (1),但如果按上述方式使用,则会泄漏内存。同样,该手册页似乎并未排除它。

解决方法

通过将单个调用替换asprintf

{
  char *newStr = NULL;
  asprintf(newStr,"%s %s",argv[i],str);
  free(str);
  str = newStr;
}

但这很笨拙。

共识实现是否保证第一个代码示例是安全正确的?

4

1 回答 1

3

它是否到处泄漏内存?

是的,它确实。

char *str = strdup(argv[i]);

这里,str包含指向malloc()应该是free()d 的 ated 内存的指针。

asprintf(&str, "%s %s", argv[i], str);

在这里,asprintf()修改str为指向函数本身分配的其他一些内存。现在您只是丢失了指向strdup()ped 字符串的指针,因此发生了泄漏。

于 2013-03-26T18:51:04.957 回答