2015-09-11 29 views
12

Mentre si lavora sul mio compilatore ho ottenuto questo errore:__memcpy_sse2_unaligned: cosa significa in dettaglio?

Program received signal SIGSEGV, Segmentation fault. 
__memcpy_sse2_unaligned() at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:33 

Come faccio ad avere i dettagli di ciò che è andato storto qui? So che dal backtrace è una riga memcpy che lo causa, ma come faccio a vedere come la memoria è allineata? E come faccio a sapere come deve essere allineato ?

Il progetto è un compilatore con un back-end LLVM che utilizza il runtime Zend/PHP con il garbage collector OCaml, quindi c'è un sacco di cose che possono andare storte.

ho il sospetto questa linea essendo parte del problema:

zend_string *str = (zend_string *)caml_alloc(ZEND_MM_ALIGNED_SIZE(_STR_HEADER_SIZE + len + 1), 0); 

dove caml_alloc erano pemalloc nel codice sorgente Zend.

Il segfault si verifica quando si eseguono 10.000 concatenazioni di stringhe. Questo è l'output di valgrind:

==7501== Invalid read of size 8 
==7501== at 0x4C2F790: [email protected]@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==7501== by 0x4D7E58: subsetphp_concat_function (bindings.c:160) 
==7501== by 0x4D7F52: foo (llvm_test.s:21) 
==7501== by 0x4D7FA9: main (llvm_test.s:60) 
==7501== Address 0x61db938 is 2,660,600 bytes inside a block of size 3,936,288 free'd 
==7501== at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==7501== by 0x4C2627: do_compaction (in /home/olle/kod/subsetphp/test) 
==7501== by 0x4C2735: caml_compact_heap (in /home/olle/kod/subsetphp/test) 
==7501== by 0x4D08DF: caml_major_collection_slice (in /home/olle/kod/subsetphp/test) 
==7501== by 0x4D2DCF: caml_minor_collection (in /home/olle/kod/subsetphp/test) 
==7501== by 0x4D2FBC: caml_check_urgent_gc (in /home/olle/kod/subsetphp/test) 
==7501== by 0x4D7C45: subsetphp_string_alloc (bindings.c:90) 
==7501== by 0x4D7CEE: subsetphp_string_init (bindings.c:122) 
==7501== by 0x4D7DEA: subsetphp_concat_function (bindings.c:149) 
==7501== by 0x4D7F52: foo (llvm_test.s:21) 
==7501== by 0x4D7FA9: main (llvm_test.s:60) 

Qualsiasi consiglio apprezzato.

Edit:

extern value subsetphp_concat_function(value v1, value v2) 
{ 

    CAMLparam2(v1, v2); 

    zend_string *str1 = Zend_string_val(v1); 
    zend_string *str2 = Zend_string_val(v2); 
    size_t str1_len = str1->len; 
    size_t str2_len = str2->len; 
    size_t result_len = str1_len + str2_len; 

    value result = subsetphp_string_init("", result_len, 1); 
    zend_string *zend_result = Zend_string_val(result); 

    if (str1_len > SIZE_MAX - str2_len) { 
    zend_error_noreturn(E_ERROR, "String size overflow"); 
    } 

    memcpy(zend_result->val, str1->val, str1_len); // This is line 160 
    memcpy(zend_result->val + str1_len, str2->val, str2_len); 
    zend_result->len = result_len; 
    zend_result->val[result_len] = '\0'; 

    CAMLreturn(result); 
} 

Edit 2:

Dal valgrind mi dà questa linea

Address 0x61db938 is 2,660,600 bytes inside a block of size 3,936,288 free'd 

Credo che sto cercando di copiare qualcosa che è già stato liberato, il che significa che non dico correttamente al GC OCaml quando qualcosa non viene più referenziato.

+0

Puoi mostrarci 'subsetphp_concat_function'? –

+0

Quando si desidera un aiuto su un errore nel codice (che alcuni sostengono non è quello per cui è Stackoverflow), includere sempre del codice (il più breve possibile) che produce il bug. – Thomash

+0

@ Mr.Llama Aggiunto. –

risposta

6

Questo errore indica che qualcosa di brutto si verifica durante memcpy, probabilmente qualcosa come un puntatore nullo o un errore nelle dimensioni.

Non preoccupatevi di __memcpy_sse2_unaligned, è un dettaglio di implementazione di memcpy. memcpy ha molte implementazioni differenti ottimizzate per i diversi casi e invia dinamicamente a quella più efficiente data il contesto. Quello sembra essere usato quando le istruzioni sse2 sono disponibili ei puntatori non sono allineati a 16 byte (le istruzioni sse2 non possono caricare valori non allineati), operazione che probabilmente viene eseguita copiando un byte alla volta fino a raggiungere un limite di 16 byte e passando a il percorso veloce.

Per quanto riguarda i dettagli specifici di OCaml gc collegati a LLVM, è necessario essere piuttosto attenti a come gestiscono i puntatori di heap. Come tu non dici se stai usando il meccanismo gcroot oi nuovi stati, suppongo tu stia usando gcroot.

Poiché OCaml gc è un collettore in movimento (passando dall'heap secondario all'heap principale e spostandosi durante la compattazione) ogni allocazione può potenzialmente invalidare un puntatore. Ciò significa che è solitamente pericoloso ridurre l'accesso al campo ai valori allocati dell'heap. Per esempio questo è sicuro:

v = field(0, x) r = function_call(...) w = field(0, v)

la funzione di chiamata potrebbe fare alcune assegnazioni che potrebbero scatenare una compattazione.

v = field(0, x) r = function_call(...) v' = field(0, x) w = field(0, v')

A proposito, io non sono nemmeno certo che il meccanismo gcroot in grado di gestire correttamente gc in movimento (che LLVM non ottimizza le cose che shouldn "t).

in modo che significa quando arrivavano che non è una buona idea usare gcroot con GC di OCaml. Il nuovo modo è migliore per quel tipo di GC, ma è necessario stare attenti a non accedere al puntatore attraverso chiamate di funzione o allocazioni

Quindi il tuo errore potrebbe essere qualcosa collegato a quel tipo di problema: il puntatore era valido ad un certo punto, quindi un valore è stato spostato duri ng compaction che ha portato alcune pagine gc inutilizzate, quindi liberate.