2013-02-15 17 views
27

I niedawno dostał się następujący błąd z mojego PHP:Co oznacza „uszkodzony lista podwójnie związane” oznaczają

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

ja nie bardzo przeszkadza ten problem, i nie bardzo interesuje go naprawić. Ale jestem bardzo zainteresowany zrozumieniem, co ten błąd "uszkodzoną podwójnie połączoną listą" w rzeczywistości oznacza, ponieważ nie widziałem go wcześniej. Wierzę, że wiem, co to jest podwójnie połączona lista, ale nie udało mi się stworzyć programu, który spowodowałby ten błąd.

Czy ktoś może podać mi krótki fragment kodu, który powoduje, że glibc wypowiada "uszkodzoną podwójnie połączoną listę" podczas kompilowania i uruchamiania?

Odpowiedz

43

znalazłem odpowiedzi na moje pytanie sam :)

Więc czego nie było zrozumieć, jak glibc mógł odróżnić się wysypać i uszkodzonych liście podwójnie związany, bo według mojego rozeznania, z w perspektywie glibc powinny wyglądać tak samo. Bo jeśli zaimplementuję podwójnie połączoną listę w moim programie, w jaki sposób glibc może wiedzieć, że jest to podwójnie połączona lista zamiast jakiejkolwiek innej struktury? Prawdopodobnie nie może, więc dlatego byłem zdezorientowany.

Teraz patrzę na malloc/malloc.c wewnątrz kodu glibc, a widzę, co następuje:

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;              \ 

Więc teraz to nagle ma sens. Powodem, dla którego glibc może wiedzieć, że jest to lista podwójnie połączona, jest fakt, że lista jest częścią samego glibc. Byłem zdezorientowany, ponieważ myślałem, że glibc może w jakiś sposób wykryć, że jakieś programowanie buduje podwójnie połączoną listę, czego nie rozumiem, jak to działa. Ale jeśli ta podwójnie powiązana lista, o której mowa, jest częścią samego glibc, oczywiście może wiedzieć, że jest to podwójnie połączona lista.

Nadal nie wiem, co spowodowało ten błąd. Ale przynajmniej rozumiem różnicę między uszkodzoną, podwójnie połączoną listą a Segfault, a sposób, w jaki glibc może znać tę strukturę, ma być podwójnie połączoną listą :)

+21

Byłoby śmieszne, gdyby glibs był taki mądry;) "Bad projekt programu" -> * trzask * – mlvljr

1

Dla każdego, kto szuka rozwiązań tutaj, ja miał podobny problem z C++: malloc(): smallbin podwójnie połączona lista uszkodzona:

Wynikało to z faktu, że funkcja nie zwracała wartości, którą miała.

Nie wiem, dlaczego udało się to skompilować. Prawdopodobnie pojawiło się ostrzeżenie.

0

Wpadłem na ten błąd w jakimś kodzie, w którym ktoś wywoływał exit() w jednym wątku w tym samym czasie, co main(), więc wszystkie konstruktory globalne/statyczne były uruchamiane jednocześnie w dwóch osobnych wątkach.

Ten błąd manifestuje się także jako double free or corruption, lub segfault/sig11 wewnątrz exit() lub wewnątrz malloc_consolidate i prawdopodobnie inne. Stos wywołań dla malloc_consolidate katastrofie może przypominać:

#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[] (...) 
(...) 

nie mogę zmusić go do wykazują ten problem podczas uruchamiania pod valgrind.

13

Przepełnienie sterty powinny być wina (ale nie zawsze) dla corrupted double-linked list, malloc(): memory corruption, double free or corruption (!prev) -jak ostrzeżeń glibc.

To powinno być powielana według następującego kodu:

#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; 
} 

jeśli skompilowany przy użyciu 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-7f00 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 

a jeśli skompilowany przy użyciu szczęk ++ (6,0 (dzyń-600.0.56)):

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

Jeśli myślałeś mógłbyś napisać taki błąd, oto kilka wskazówek, jak go wyśledzić.

pierwsze, skompilować kod z flagą debugowania (-g):

g++ -g foo.cpp 

a następnie uruchomić go za pomocą 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) 

Błąd znajduje się w == == na 12693 0x400A25: główny (foo.cpp: 11)

0

Może to być spowodowane różnymi przyczynami, niektórzy twierdzą, że inni kandydaci i ja wprowadzę duce my case:

Ten błąd występuje podczas korzystania z wielowątkowości (zarówno std::pthread, jak i std::thread) i wystąpił błąd, ponieważ zapomniałem zablokować zmienną, która może zmieniać wiele wątków w tym samym czasie. ten błąd pojawia się losowo w niektórych seriach, ale nie wszystkie, ponieważ ... wiesz, że wypadek między wątkami jest losowy.

Zmienna w moim przypadku była globalna std::vector, którą próbowałem do push_back() coś w nim w funkcji wywoływanej przez wątki .. a następnie użyłem std::mutex i nigdy nie otrzymałem tego błędu ponownie.

może pomóc niektórym