什么是 glibc free/malloc/realloc invalid next size/invalid pointer error 以及如何修复它?

2021-12-21 00:00:00 memory c c++ glibc

您很可能会看到此问题,因为您的问题已作为此问题的副本关闭.有关中等完整的相关问题列表,请参阅 Meta Stack Overflow 上的一长串可能的重复项――C 内存分配和溢出边界.

来自免费字符*:下一个尺寸无效(快速) 由 noobie 于 2014 年 4 月 11 日询问.

From free char*: invalid next size (fast) asked by noobie on 2014-04-11.

我在连接过程后释放 char*,但收到此错误:

I am freeing a char* after a concatenation process, but I receive this error:

free(): invalid next size (fast): 0x0000000001b86170

这是我的代码:

void concat(stringList *list) {
    char *res = (char*)malloc(sizeof(char*));

    strcpy(res, list->head->string);

    list->tmp = list->head->next;
    while (list->tmp != NULL) {
        strcat(res, ",");
        strcat(res, list->tmp->string);
        list->tmp = list->tmp->next;
    }

    printf("%s
", res);
    free(res);
}

<小时>

一般问题

在运行我的程序时,我看到如下错误消息:


Generic Question

When running my program, I see an error message like this:

*** glibc detected *** ./a.out: free(): corrupted unsorted chunks: 0x12345678 ***

详细信息在*** glibc detection ***和程序名之后可以包含以下任意一个,并且消息后跟一个十六进制地址(显示为0x12345678)和另一个***:

The detailed information can contain any of the following after the *** glibc detected *** and the program name, and the message is followed by a hexadecimal address (shown as 0x12345678) and another ***:

  • free():损坏的未排序块:0x12345678
  • free():下一个尺寸无效(快速):0x12345678
  • free():下一个尺寸无效(正常):0x12345678
  • free(): 无效指针:0x12345678
  • free(): 无效尺寸:0x12345678
  • malloc():损坏的未排序块:0x12345678
  • malloc(): 损坏的未排序块 2: 0x12345678
  • malloc():内存损坏:0x12345678
  • malloc():内存损坏(快速):0x12345678
  • malloc():smallbin 双链表损坏:0x12345678
  • munmap_chunk(): 无效指针:0x12345678
  • realloc():下一个尺寸无效(快速):0x12345678
  • realloc():无效的旧大小(快速):0x12345678
  • realloc(): 无效指针:0x12345678
  • 损坏的双链表:0x12345678

这是在调用 frobnicate() 函数时发生的;这个函数有什么问题?

This happens while calling the frobnicate() function; what is wrong with that function?

推荐答案

示例题答案

unwind 给出了接受的 回答示例问题:

Answer for Example Question

unwind gave the accepted answer to the example question:

您的代码有误.

您正在为单个指针 (malloc(sizeof(char*))) 分配空间,但没有字符.您正在用所有字符串覆盖分配的空间,导致未定义的行为(在这种特殊情况下,破坏了 malloc() 的簿记数据).

You are allocating space for a single pointer (malloc(sizeof(char*))), but no characters. You are overwriting your allocated space with all the strings, causing undefined behavior (in this particular case, corrupting malloc()'s book-keeping data).

不需要为指针分配空间(res);它是一个局部变量.您必须为您希望存储在指针持有的地址处的所有字符分配空间.

You don't need to allocate space for the pointer (res); it's a local variable. You must allocate space for all the characters you wish to store at the address held by the pointer.

由于您要遍历列表以查找要连接的字符串,因此您无法预先知道总大小.您将不得不对列表执行两次传递:一次对每个字符串的 strlen() 求和,然后为分隔符和终止符分配该加空间,然后在实际执行时再一次传递串联.

Since you're going to be traversing a list to find strings to concatenate, you can't know the total size upfront. You're going to have to do two passes over the list: one to sum the strlen() of each string, then allocate that plus space for the separator and terminator, then another pass when you actually do the concatenation.

通用答案

您所看到的是 glibc 分配器内部结构损坏的结果.当您分配或释放动态内存时,分配器必须管理它从操作系统保留的内存,并根据您请求的操作,找到要分发的新块,将释放的块分类到它的列表中可以稍后再分发,或者将内存还给操作系统.这些错误消息表明它用于管理此功能的数据结构已损坏.

Generic Answer

What you are seeing is the result of a corruption in the internal structures of the glibc allocator. When you are allocating or freeing dynamic memory, the allocator has to manage the memory it reserved from the OS and, depending on the action requested by you, find a new chunk to hand out, sort a freed chunk into the list of those that it can hand out later again, or give the memory back to the operating system. These error messages show that the data structures it uses to manage this functionality are corrupted.

这些错误都意味着您的某些代码修改了未给它使用的内存,从而调用了未定义的行为.这很可能是程序中较早覆盖一些内存的结果,并且错误完全有可能不在 frobnicate() 函数中.

These errors all mean that some of your code has modified memory that it was not given to use, invoking undefined behaviour. This is most likely the result of overwriting some memory quite a bit earlier in your program, and it is totally possible that the error does not lie in the frobnicate() function.

是的,这意味着错误可能出现在您的程序或您使用的第 3 方库中的任何地方.

Yes, this means that the error can be anywhere in your program or 3rd party libraries you use.

这对于 Stack Overflow 来说可能不是一个好问题.除非你对你的问题有一个很好的简单再现,否则这个社区可能无法帮助你.错误的原因可能在您的代码中的任何地方(并且通常不在发现错误的函数中),也可能在我们看不到的代码中.Stack Overflow不是一个协作调试站点.即使有人能发现您代码中的缺陷,您的具体问题也不太可能对任何未来的访问者有帮助.

This is probably not a good question for Stack Overflow. Unless you have a good simple reproduction of your problem, this community may be unable to help you very much. The cause of the error can be anywhere in your code (and is very often not in the function where the error is spotted), and it may be in code that we cannot see. Stack Overflow is not a collaborative debugging site. Even when someone can find the flaw in your code, it is unlikely that your specific question will ever help any future visitor.

  • 释放后使用.您已经释放/删除了一些内存并在之后写入其中,覆盖了 glibc 记账所需的结构.
  • Off-by-N 错误.您正在将分配的块之后的 N 个字节写入未分配的内存中,glibc 在内部使用该内存进行簿记.
  • 未初始化的指针.您没有初始化指针.巧合的是,它指向了一些由 glibc 保留但未由您的程序分配的内存,并且您写入了它.
  • 分配了错误的空间量.这可能是因为您编写了 long *data = malloc(number * 4) 而不是 long *data = malloc(number * sizeof(long)); 或(更好)long *data = malloc(number * sizeof(*data));.还有许多其他方法可以使大小计算错误.另一种常见的情况是忘记考虑字符串末尾的空终止符:char *copy = malloc(strlen(str)); 而不是 char *copy = malloc(strlen(str)+1);.
  • Use after free. You have freed/deleted some memory and writing into it afterwards, overwriting the structures glibc needs for bookkeeping.
  • Off-by-N error. You are writing N bytes after an allocated chunk into unallocated memory that glibc uses internally for its bookkeeping.
  • Uninitialized pointers. You are not initializing a pointer. By coincidence it points to some memory reserved by glibc but not allocated by your program and you write to it.
  • Allocating the wrong amount of space. This can be because you wrote long *data = malloc(number * 4) instead of long *data = malloc(number * sizeof(long)); or (better) long *data = malloc(number * sizeof(*data));. There are many other ways to get the size calculation wrong. Another common one is to forget to account for the null terminator character at the end of a string: char *copy = malloc(strlen(str)); instead of char *copy = malloc(strlen(str)+1);.

你现在需要做的是挽起袖子,调试那个问题

没有简单的答案来寻找或修复什么.您没有使用错误的单一语法结构.这个错误的原因实际上可以有数千种.

There is no simple answer what to look for, or what to fix. No single syntactical construct that you were using wrong. The cause of this bug can come in literally thousands of varieties.

  • valgrind 一种主要用于准确查找此类错误的工具.如果找不到任何内容,请确保您使用的是最新版本,并且您也在尝试包含的 exp-sgcheck 工具.如果您正在运行多线程代码,原因也可能与竞争条件有关,因此您可能需要尝试包含的竞争条件检查器 drdhelgrind 以获得更多见解.在撰写本文时,valgrind 支持以下平台:
    • X86/Linux,
    • AMD64/Linux,
    • ARM/Linux,
    • PPC32/Linux,
    • PPC64/Linux,
    • S390X/Linux,
    • MIPS32/Linux,
    • MIPS64/Linux,
    • ARM/Android(2.3.x 及更高版本),
    • X86/Android(4.0 及更高版本),
    • X86/达尔文和
    • AMD64/Darwin(Mac OS X 10.7,对 10.8 的支持有限).
    • valgrind A tool created mostly for the purpose of finding exactly this kinds of errors. If it can't find anything make sure you are using the latest version, and you are also trying out the included exp-sgcheck tool. If you are running multithreaded code, the cause might also be related to a race condition so you might want to try the included race condition checkers drd and helgrind for more insight. At the point of writing this, valgrind supports the following platforms:
      • X86/Linux,
      • AMD64/Linux,
      • ARM/Linux,
      • PPC32/Linux,
      • PPC64/Linux,
      • S390X/Linux,
      • MIPS32/Linux,
      • MIPS64/Linux,
      • ARM/Android (2.3.x and later),
      • X86/Android (4.0 and later),
      • X86/Darwin and
      • AMD64/Darwin (Mac OS X 10.7, with limited support for 10.8).

      如果您无法使用这些工具解决问题,您应该尝试创建一个 MCVE(如何创建最小、完整、和可验证示例?)或等效的 SSCCE(简短、自包含、正确(可编译)、示例).

      If you can't solve your problem using one these tools, you should try to create an MCVE (How to create a Minimal, Complete, and Verifiable Example?) or, equivalently, an SSCCE (Short, Self Contained, Correct (Compilable), Example).

      请记住处理您的代码副本,因为创建 MCVE 需要您无情地删除无助于重现问题的代码.使用 VCS(版本控制系统)来辅助是个好主意;您可以记录将问题减少到最低限度的中间阶段.它可能是一个新的一次性存储库,只是为了将您的问题减少到可管理的规模.

      Remember to work on a copy of your code because creating an MCVE requires you to ruthlessly remove code that does not help reproduce the problem. Using a VCS (version control system) to assist is a good idea; you can record intermediate stages in reducing the problem to a minimum. It might be a new throw-away repository just for reducing your problem to a manageable size.

      通过对代码进行良好的模块化设计,创建 MCVE 应该相对容易.也许您也已经有了一个更适合输入上述工具之一的单元测试.您也可能只想创建一个以后可以用作此错误的回归测试.

      With a good modular design to your code, it should be relatively easy to create the MCVE. Maybe you also already have a unit test that is better suited to be fed into one of the above tools. You also might just want to create one that can later serve as a regression test for this bug.

相关文章