2012-01-19 21 views
5

Występuje dziwna sytuacja z przekazaniem wskaźnika do struktury o bardzo dużej tablicy zdefiniowanej w definicji struct {}, tablicy typu float o rozmiarze około 34 MB. W skrócie, psuedo Kod wygląda następująco:Dziwne przepełnienie stosu?

typedef config_t{ 
    ... 
    float values[64000][64]; 
} CONFIG; 


int32_t Create_Structures(CONFIG **the_config) 
{ 
    CONFIG *local_config; 
    int32_t number_nodes; 

    number_nodes = Find_Nodes(); 

    local_config = (CONFIG *)calloc(number_nodes,sizeof(CONFIG)); 
    *the_config = local_config; 
    return(number_nodes); 
} 


int32_t Read_Config_File(CONFIG *the_config) 
{ 
    /* do init work here */ 
    return(SUCCESS); 
} 


main() 
{ 
    CONFIG *the_config; 
    int32_t number_nodes,rc; 

    number_nodes = Create_Structures(&the_config); 

    rc = Read_Config_File(the_config); 
    ... 
    exit(0); 
} 

Kod kompiluje grzywny, ale gdy próbuję go uruchomić, Wezmę SIGSEGV u {pod Read_Config_File().

(gdb) run 
... 
Program received signal SIGSEGV, Segmentation fault. 
0x0000000000407d0a in Read_Config_File (the_config=Cannot access memory at address 0x7ffffdf45428 
) at ../src/config_parsing.c:763 
763 { 
(gdb) bt 
#0 0x0000000000407d0a in Read_Config_File (the_config=Cannot access memory at address 0x7ffffdf45428 
) at ../src/config_parsing.c:763 
#1 0x00000000004068d2 in main (argc=1, argv=0x7fffffffe448) at ../src/main.c:148 

Robiłem tego rodzaju rzeczy przez cały czas, z mniejszymi tablicami. I dziwnie, 0x7fffffffe448 - 0x7ffffdf45428 = 0x20B8EF8 lub około 34 MB mojej tablicy float.

Valgrind da mi podobny wynik:

==10894== Warning: client switching stacks? SP change: 0x7ff000290 --> 0x7fcf47398 
==10894==   to suppress, use: --max-stackframe=34311928 or greater 
==10894== Invalid write of size 8 
==10894== at 0x407D0A: Read_Config_File (config_parsing.c:763) 
==10894== by 0x4068D1: main (main.c:148) 
==10894== Address 0x7fcf47398 is on thread 1's stack 

komunikaty o błędach wszystko wskazuje na mnie clobbering wskaźnik stosu, ale a) Nigdy nie natknąć się taki, który rozbija się na wejściu funkcji oraz b) Przekazuję wskaźniki, a nie rzeczywistą tablicę.

Czy ktoś może mi w tym pomóc? Jestem na 64-bitowym pudełku CentOS z jądrem 2.6.18 i gcc 4.1.2

Dzięki!

Matt

+9

Wysyłanie pseudokodu dostarcza tylko pseudo-odpowiedzi. Diabeł tkwi w szczegółach i prawdopodobnie wszystkie będą ważne. –

+2

Czy moglibyśmy zobaczyć źródło 'Read_Config_File'? W tym miejscu wydaje się, że problem leży w bloku, z którego zrezygnowałeś. – Borealid

+0

Nie testujesz wartości zwracanej przez calloc(), która może się nie powieść. –

Odpowiedz

1

Wysunąłeś stos, przypisując do niego jedną z tych ogromnych struktur config_t. Dwa wskaźniki stosu na dowodach w danych wyjściowych gdb, 0x7fffffffe448 i 0x7ffffdf45428, są bardzo sugestywne.

$ gdb 
GNU gdb 6.3.50-20050815 ...blahblahblah... 
(gdb) p 0x7fffffffe448 - 0x7ffffdf45428 
$1 = 34312224 

Istnieje twoja stała ~ 34 MB, która odpowiada rozmiarowi struktury config_t. Systemy nie dają domyślnie tyle miejsca na stos, więc albo przenieś obiekt ze stosu, albo zwiększ przestrzeń stosu.

+0

Czy istnieje narzędzie przypominające "kłaczków", które może mi powiedzieć, ile żetonu funkcja pożera? Z perspektywy czasu jest już oczywiste, co to za usterka, ale chciałbym wiedzieć z góry, czy takie problemy istnieją. – tranzmatt

+0

gcc ma -fstack-limit- * dla sprawdzania w czasie działania, ale nic nie wiem, który ostrzega o nadmiernie dużych alokacjach stosów podczas kompilacji. –

1

Krótka odpowiedź jest taka, że ​​musi istnieć config_t zadeklarowane jako zmiennej lokalnej gdzieś, co byłoby umieścić go na stosie. Prawdopodobnie literówka: brakująca * po deklaracji CONFIG gdzieś.

+0

To był problem. Zapomniałem, że zachowałem tymczasową kopię struktury config_t w funkcji przed zablokowaniem tablicy wewnątrz. Przeniosłem tablicę gdzie indziej i teraz nie wykreśla błędu. Dzięki. – tranzmatt

Powiązane problemy