2015-09-11 41 views
12

Während ich diesen Fehler hätte auf meinem Compiler arbeiten:__memcpy_sse2_unaligned - was bedeutet das im Detail?

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

Wie komme ich Details von dem, was hier schief gelaufen ist? Ich weiß aus dem Backtrace ist es eine memcpy Zeile, die es verursacht, aber wie kann ich sehen, wie der Speicher ausgerichtet ist? Und woher weiß ich, wie es sollte ausgerichtet werden?

Das Projekt ist ein Compiler mit einem LLVM-Backend, das die Zend/PHP-Laufzeit mit dem OCaml-Garbage-Collector verwendet, also gibt es eine Menge Dinge, die schief gehen können.

Ich vermute, dass diese Linie ein Teil des Problems zu sein:

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

wo caml_alloc waren pemalloc in der Zend-Quellcode.

Der segfault tritt auf, wenn 10'000 String-Verkettungen ausgeführt werden. Dies ist die Ausgabe von 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) 

Alle Tipps geschätzt.

bearbeiten:

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:

Da valgrind gibt mir diese Linie

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

Ich denke, ich versuche, etwas zu kopieren, das bereits befreit, was bedeutet, dass ich dem OCaml GC nicht korrekt sage, wenn etwas nicht mehr referenziert wird.

+0

Können Sie uns 'subsetphp_concat_function' zeigen? –

+0

Wenn Sie Hilfe zu einem Fehler in Ihrem Code benötigen (der nicht unbedingt der Meinung von Stackoverflow ist), sollten Sie immer einen Code (so kurz wie möglich) einfügen, der den Fehler verursacht. – Thomash

+0

@ Mr.Llama Hinzugefügt. –

Antwort

6

Dieser Fehler sagt Ihnen, dass während memcpy etwas Schlimmes passiert ist, wahrscheinlich etwas wie ein Nullzeiger oder ein Fehler in den Größen.

Stören Sie nicht mit __memcpy_sse2_unaligned, es ist ein Implementierungsdetail von memcpy. memcpy hat viele verschiedene Implementierungen, die für die verschiedenen Fälle optimiert sind und dynamisch an den effizientesten im Kontext verteilt werden. Dieser scheint verwendet zu werden, wenn sse2-Befehle verfügbar sind und Zeiger nicht auf 16-Byte-Grenzen ausgerichtet sind (sse2-Befehle können nicht ausgerichtete Werte nicht laden), was wahrscheinlich durch Kopieren von jeweils einem Byte bis zum Erreichen einer 16-Byte-Grenze erfolgt der schnelle Weg.

Wie für die OCaml gc spezifische Details mit LLVM verbunden sind, müssen Sie sehr vorsichtig sein, wie Sie mit Heap-Zeigern umgehen. Da Sie nicht wissen, ob Sie den Gcroot-Mechanismus oder die neuen Statuspunkte verwenden, nehme ich an, dass Sie gcroot verwenden.

Da der OCaml-GC ein beweglicher Collector ist (der sich vom Minor-Heap zum Major-Heap bewegt und sich während der Komprimierung bewegt), kann jede Zuweisung möglicherweise einen Zeiger ungültig machen. Das bedeutet, dass es normalerweise nicht sicher ist, den Feldzugriff auf zugewiesene Heap-Werte zu factorisieren. Zum Beispiel ist dies unsicher:

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

der Funktionsaufruf einige Zuweisungen tun könnte, die eine Verdichtung auslösen könnte.

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

By the way, ich bin nicht einmal sicher, dass der gcroot Mechanismus richtig bewegen gc verarbeiten kann (das llvm optimieren nicht Dinge, die es shouldn "t).

Damit die usualy Mittel dass es keine gute Idee ist, gcroot mit OCaml's GC zu verwenden. Der neue Weg ist besser für diese Art von GC, aber Sie müssen immer vorsichtig sein, nicht auf Zeiger über Funktionsaufrufe oder Zuordnungen zuzugreifen.

So kann Ihr Fehler sein etwas, das mit dieser Art von Problem verbunden war: der Zeiger war irgendwann gültig, dann wurde ein Wert verschoben ng Verdichtung, die dazu führte, dass einige gc-Seiten nicht verwendet wurden und somit freigegeben wurden.