Vin*_*ent 1 c macos printf gcc
我正在尝试将应用程序从Linux移植到Mac Os X(leopard),但是当我执行它时,我有这样的错误消息:malloc: *** error for object 0x100160 : double free.
我用下面的代码重现了这个问题:
//main.cpp
#include <stdio.h>
#include <wchar.h>
int main(int argc, char*argv[])
{
wchar_t *b=NULL;
printf("a=%ls, b=%ls \n", L"a", b);
}
Run Code Online (Sandbox Code Playgroud)
用gcc编译:
gcc main.cpp -o test
Run Code Online (Sandbox Code Playgroud)
执行的输出:
a=a, b=(null)
test (5337) malloc: *** error for object 0x100160 : double free
*** set a breakpoint in malloc_error_break to debug
Run Code Online (Sandbox Code Playgroud)
这很奇怪,因为如果我使用这一行:printf("a=%ls, b=%ls", b, b),不会打印错误.而且,我不能用wprintf(L"a=%ls, b=%ls", a, b).在Fedora 13上,该程序不会输出任何错误.
这是一个printf bug吗?如何删除此错误?
您不能将NULL指针打印为字符串,这是未定义的行为.根据C99标准,§7.19.6.1/ 8
转换说明符及其含义为:
...
s 如果不存在l长度修饰符,则参数应为指向字符类型数组的初始元素的指针....如果存在
l长度修饰符,则参数应该是指向wchar_t类型数组的初始元素的指针.
由于未明确允许NULL指针,因此不允许使用它们.您应该将代码更改为:
printf("a=%ls, b=%ls \n", L"a", b ? b : L"(null)");
Run Code Online (Sandbox Code Playgroud)
小智 5
这只是一个错误vprintf_l,处理printf(可能是它的所有朋友).
严格来说,图书馆有权通过做任何它喜欢的事情来处理这种情况,包括堆腐败,但是根据代码来判断意图 - 对于任何非垃圾printf实现应该是这种情况- 是NULL明智地处理字符串.代码中只有一个错误就是这样做.这些事情发生了.
如果在打印了NULL前一个非宽字符指针后尝试打印宽字符指针NULL,vprintf_l则会在下一个字符串参数或vprintf_l退出时启动.(可能还有其他方法可以实现这一点,我想 - 我没有检查.)
违规代码在这里:
case 's':
if (flags & LONGINT) {
wchar_t *wcp;
if (convbuf != NULL)
free(convbuf);
if ((wcp = GETARG(wchar_t *)) == NULL)
cp = "(null)";
else {
convbuf = __wcsconv(wcp, prec, loc);
if (convbuf == NULL) {
fp->_flags |= __SERR;
goto error;
}
cp = convbuf;
}
} else if ((cp = GETARG(char *)) == NULL)
Run Code Online (Sandbox Code Playgroud)
如果GETARG(wchar_t *)返回NULL,convbuf将指向旧的(现在释放的)缓冲区.然后,当函数退出时,有一个双重释放:
if (convbuf != NULL)
free(convbuf);
Run Code Online (Sandbox Code Playgroud)
如果有另一个字符串参数,则同样适用,但在这种情况下,case 's'上面的代码中会发生双重自由:
printf("a=%ls, b=%ls c=%ls\n", L"a", b, L"c");
Run Code Online (Sandbox Code Playgroud)
当然,解决办法是设置convbuf到NULL它被释放之后.
该printf代码是在这里:
http://www.opensource.apple.com/source/Libc/Libc-594.1.4/stdio/vfprintf-fbsd.c
通过反汇编来判断,它是用于Snow Leopard中默认运行时的代码.