realloc(): 重新分配内存空间时出现无效的下一个大小,用于扩展 char * 中的 strcat。

17

以下代码导致了无效的内存错误:

printf(" %s\n","FINE 5");
printf("%s LENGTH IS: %d\n","FINE 6",strlen(": "));
buffer = (char *)realloc(buffer, strlen(buffer)* sizeof(char) + (strlen(": ")+1)* sizeof(char));
printf(" %s\n","FINE 7");
strcat(buffer, ": \0");

输出:

FINE 5
FINE 6 LENGTH IS: 2
* glibc detected * ./auto: realloc(): invalid next size: 0x08cd72e0 *** ======= Backtrace: ========= /lib/tls/i686/cmov/libc.so.6(+0x6b591)[0x6dd591]

这里需要注意的是,Fine 7从未被打印出来。每次运行都在同一位置出现了无效的下一个大小错误。

发现这个很相关。


1
在调用realloc之前,buffer设置为什么? - Brett Hale
1
这是一个指针,我一直在重新分配它,其中大约有20个字符被正确打印。 - PUG
此外,您应该测试realloc失败的情况。虽然不太可能,但确实会发生。 - Adrian Cornish
3个回答

21

这个错误是由于代码的其他部分破坏了堆而导致的。如果没有看到代码的其他部分,我们无法告诉您那个错误是什么。

未打印“FINE 7”这一事实告诉您,realloc失败了。而且,由于在执行早期存在堆破坏,所以buffer无效导致失败。


与您实际问题无关的是,按定义sizeof(char)1,因此从代码中删除它是有意义的。


@ David Heffernan 缓冲区中的数据直到打印“Fine 6”为止。 - PUG
2
如果没有堆损坏,realloc 就会成功。缓冲区可以正常打印,但是内存块的元数据已经损坏。当分配内存时,分配器内部还会有一个头块。这就是被破坏的内容。总之,我已经表达了我的观点很多次了。 - David Heffernan
1
我之前使用了 strncpy(arr, arrTemp, strlen(arrtTemp)),但应该使用 strncpy(arr, arrTemp, strlen(arrtTemp)+1)。 - PUG

9
正如David Heffernan指出的那样,你的根本问题必须是你代码中的其他任何地方都有一个破坏堆的野指针。
这段代码还有几个值得考虑的地方。
  1. No need for sizeof (char) in the new size expression, as sizeof (char) is, by definition, 1.

  2. Never assign the return from realloc directly back to the only pointer to the buffer you're reallocating. If realloc returns NULL on an error, you'll lose your pointer to the old buffer, and gain your very own memory leak. You always want to do the appropriate equivalent of:

    footype *p = realloc(oldbuff, newsize);
    if (!p) {
        handle_error();
    } else {
        oldbuff = p;
    }
    
  3. In C, void * will automatically be converted to the correct type on assignment, there is no need to cast. Further, by casting, in some cases you won't get helpful error messages when you forget to include the declaration of the function in question.

  4. String literals include an implied nul terminator. You wanted to say:

    strcat(buffer, ": ");

好的,就这一点而言,strcat函数会在第一个空字符处停止,因此在这种情况下不会有任何问题。


通过包含额外的\0来避免缓冲区溢出。 strcat将继续到第一个\0,它永远不会看到第二个\0。您可以在其中放置任意数量的零终止符。 - David Heffernan
啊...当然,strcat会在要复制的字符串中第一个nul处停止。我会更正我的答案并提醒自己在工作时回答问题是个坏主意! - Greg Jandl
@已经尝试过了,没有任何区别。 - PUG
@jaminator 不要被所有关于 strcat 的讨论所迷惑。问题出现在你的代码中,你破坏了堆栈。这不是你在这里发布的代码中的问题。 - David Heffernan
1
David是正确的 - 你有一个野指针在别处破坏了你的堆。 - Greg Jandl

0

(char *)realloc(buffer, strlen(buffer)* sizeof(char) + (strlen(": ")+1)* sizeof(char));

应该改为

(char *)realloc(buffer, (strlen(buffer) + strlen(": ") + 1) * sizeof(char));

不是吗?你计算字符串长度的数学有误。


并非如此,因为ac + bc == (a+b)*c。 - David Heffernan
1
这些语句是等价的。 - Brett Hale
1
无关紧要,因为 char = 1 字节。a * 1 = a - Jonathon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接