Подтвердить что ты не робот

Что означает "поврежденный двойной список"

Недавно я получил следующую ошибку от моего PHP:

WARNING: [pool www] child 42475 said into stderr: "*** glibc detected *** php-fpm: pool www: corrupted double-linked list: 0x00000000013fe680 ***"

Я не очень обеспокоен этой проблемой и не очень заинтересован в ее исправлении. Но мне очень интересно понять, что означает "поврежденный двойной список" этой ошибки, потому что я этого раньше не видел. Я считаю, что знаю, что такое двойной список, но я не смог создать программу, которая запускает эту ошибку.

Может ли кто-нибудь предоставить мне короткий фрагмент кода, который заставляет glibc говорить "поврежденный двойной список" при компиляции и его выполнении?

4b9b3361

Ответ 1

Я сам нашел ответ на свой вопрос:)

Так что я не понял, как glibc мог различать Segfault и поврежденный двойной список, потому что, согласно моему пониманию, с точки зрения glibc они должны выглядеть как одно и то же. Потому что, если я реализую двойной список внутри моей программы, как glibc, возможно, знает, что это список с двойной связью, а не любая другая структура? Это, вероятно, не может, поэтому вот почему я был в замешательстве.

Теперь я посмотрел malloc/malloc.c внутри кода glibc, и я вижу следующее:

1543 /* Take a chunk off a bin list */
1544 #define unlink(P, BK, FD) {                                            \
1545   FD = P->fd;                                                          \
1546   BK = P->bk;                                                          \
1547   if (__builtin_expect (FD->bk != P || BK->fd != P, 0))                \
1548     malloc_printerr (check_action, "corrupted double-linked list", P); \
1549   else {                                                               \
1550     FD->bk = BK;                                                       \
1551     BK->fd = FD;                                                       \

Итак, теперь это внезапно имеет смысл. Причина, по которой glibc может знать, что это двойной список, состоит в том, что этот список является частью самого glibc. Я был смущен, потому что думал, что glibc может каким-то образом обнаружить, что какое-то программирование создает двойной список, который я бы не понял, как это работает. Но если этот список с двойной связью, о котором идет речь, является частью самого glibc, он, конечно, может знать, что это двойной список.

Я до сих пор не знаю, что вызвало эту ошибку. Но, по крайней мере, я понимаю разницу между поврежденным двойным списком и Segfault, и как glibc может знать, что эта структура должна быть двойным списком:)

Ответ 2

Переполнение кучи должно быть виновно (но не всегда) для предупреждений [glibc] corrupted double-linked list, malloc(): memory corruption, double free or corruption (!prev) -like.

Он должен быть воспроизведен с помощью следующего кода:

#include <vector>

using std::vector;


int main(int argc, const char *argv[])
{
    int *p = new int[3];
    vector<int> vec;
    vec.resize(100);
    p[6] = 1024;
    delete[] p;
    return 0;
}

если скомпилировано с использованием g++ (4.5.4):

$ ./heapoverflow
*** glibc detected *** ./heapoverflow: double free or corruption (!prev): 0x0000000001263030 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7af26)[0x7f853f5d3f26]
./heapoverflow[0x40138e]
./heapoverflow[0x400d9c]
./heapoverflow[0x400bd9]
./heapoverflow[0x400aa6]
./heapoverflow[0x400a26]
/lib64/libc.so.6(__libc_start_main+0xfd)[0x7f853f57b4bd]
./heapoverflow[0x4008f9]
======= Memory map: ========
00400000-00403000 r-xp 00000000 08:02 2150398851                         /data1/home/mckelvin/heapoverflow
00602000-00603000 r--p 00002000 08:02 2150398851                         /data1/home/mckelvin/heapoverflow
00603000-00604000 rw-p 00003000 08:02 2150398851                         /data1/home/mckelvin/heapoverflow
01263000-01284000 rw-p 00000000 00:00 0                                  [heap]
7f853f559000-7f853f6fa000 r-xp 00000000 09:01 201329536                  /lib64/libc-2.15.so
7f853f6fa000-7f853f8fa000 ---p 001a1000 09:01 201329536                  /lib64/libc-2.15.so
7f853f8fa000-7f853f8fe000 r--p 001a1000 09:01 201329536                  /lib64/libc-2.15.so
7f853f8fe000-7f853f900000 rw-p 001a5000 09:01 201329536                  /lib64/libc-2.15.so
7f853f900000-7f853f904000 rw-p 00000000 00:00 0
7f853f904000-7f853f919000 r-xp 00000000 09:01 74726670                   /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.1/libgcc_s.so.1
7f853f919000-7f853fb19000 ---p 00015000 09:01 74726670                   /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.1/libgcc_s.so.1
7f853fb19000-7f853fb1a000 r--p 00015000 09:01 74726670                   /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.1/libgcc_s.so.1
7f853fb1a000-7f853fb1b000 rw-p 00016000 09:01 74726670                   /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.1/libgcc_s.so.1
7f853fb1b000-7f853fc11000 r-xp 00000000 09:01 201329538                  /lib64/libm-2.15.so
7f853fc11000-7f853fe10000 ---p 000f6000 09:01 201329538                  /lib64/libm-2.15.so
7f853fe10000-7f853fe11000 r--p 000f5000 09:01 201329538                  /lib64/libm-2.15.so
7f853fe11000-7f853fe12000 rw-p 000f6000 09:01 201329538                  /lib64/libm-2.15.so
7f853fe12000-7f853fefc000 r-xp 00000000 09:01 74726678                   /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.1/libstdc++.so.6.0.18
7f853fefc000-7f85400fb000 ---p 000ea000 09:01 74726678                   /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.1/libstdc++.so.6.0.18
7f85400fb000-7f8540103000 r--p 000e9000 09:01 74726678                   /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.1/libstdc++.so.6.0.18
7f8540103000-7f8540105000 rw-p 000f1000 09:01 74726678                   /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.1/libstdc++.so.6.0.18
7f8540105000-7f854011a000 rw-p 00000000 00:00 0
7f854011a000-7f854013c000 r-xp 00000000 09:01 201328977                  /lib64/ld-2.15.so
7f854031c000-7f8540321000 rw-p 00000000 00:00 0
7f8540339000-7f854033b000 rw-p 00000000 00:00 0
7f854033b000-7f854033c000 r--p 00021000 09:01 201328977                  /lib64/ld-2.15.so
7f854033c000-7f854033d000 rw-p 00022000 09:01 201328977                  /lib64/ld-2.15.so
7f854033d000-7f854033e000 rw-p 00000000 00:00 0
7fff92922000-7fff92943000 rw-p 00000000 00:00 0                          [stack]
7fff929ff000-7fff92a00000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
[1]    18379 abort      ./heapoverflow

и если скомпилировано с использованием клана g++ (6.0 (clang-600.0.56)):

$  ./heapoverflow
[1]    96277 segmentation fault  ./heapoverflow

Если вы подумали, что, возможно, написали такую ошибку, вот несколько советов, чтобы отследить ее.

Сначала скомпилируйте код с флагом отладки (-g):

g++ -g foo.cpp

А затем запустите его, используя valgrind:

$ valgrind ./a.out
==12693== Memcheck, a memory error detector
==12693== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==12693== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==12693== Command: ./a.out
==12693==
==12693== Invalid write of size 4
==12693==    at 0x400A25: main (foo.cpp:11)
==12693==  Address 0x5a1c058 is 12 bytes after a block of size 12 alloc'd
==12693==    at 0x4C2B800: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==12693==    by 0x4009F6: main (foo.cpp:8)
==12693==
==12693==
==12693== HEAP SUMMARY:
==12693==     in use at exit: 0 bytes in 0 blocks
==12693==   total heap usage: 2 allocs, 2 frees, 412 bytes allocated
==12693==
==12693== All heap blocks were freed -- no leaks are possible
==12693==
==12693== For counts of detected and suppressed errors, rerun with: -v
==12693== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Ошибка находится в == 12693 == в 0x400A25: main (foo.cpp: 11)

Ответ 3

Это может быть вызвано разными причинами, некоторые из них упомянули других кандидатов, и я представлю свое дело:

Я получил эту ошибку при использовании многопоточности (как std::pthread, так и std::thread), и ошибка произошла, потому что я забыл заблокировать переменную, которая может изменяться одновременно несколькими потоками. эта ошибка возникает случайно в некоторых прогонах, но не во всех, потому что... вы знаете, что случайность между потоками является случайной.

Эта переменная в моем случае была глобальным std::vector, который я пытался push_back() что-то в ней использовать в функции, вызываемой потоками... а затем я использовал std::mutex и больше никогда не получал эту ошибку.

может помочь некоторым

Ответ 4

Для тех, кто ищет решения здесь, у меня была аналогичная проблема с С++:  malloc(): smallbin двойной связанный список поврежден:

Это вызвано функцией, не возвращающей значение, которое оно должно было.

std::vector<Object> generateStuff(std::vector<Object>& target> {
  std::vector<Object> returnValue;
  editStuff(target);
  // RETURN MISSING
}

Не знаю, почему это удалось скомпилировать. Вероятно, было предупреждение об этом.

Ответ 5

Я столкнулся с этой ошибкой в ​​некотором коде, где кто-то вызывал exit() в одном потоке примерно в то же время, что и main(), поэтому все глобальные/статические конструкторы запускались одновременно в двух отдельных потоках.

Эта ошибка также проявляется как double free or corruption или segfault/sig11 внутри exit() или внутри malloc_consolidate и, возможно, другие. Столб вызовов для сбоя malloc_consolidate может напоминать:

#0  0xabcdabcd in malloc_consolidate () from /lib/libc.so.6
#1  0xabcdabcd in _int_free () from /lib/libc.so.6
#2  0xabcdabcd in operator delete (...)
#3  0xabcdabcd in operator delete[] (...)
(...)

Я не мог заставить его проявить эту проблему во время работы под valgrind.