2015-09-11 56 views
12

雖然在我的編譯器工作,我得到這個錯誤:__memcpy_sse2_unaligned - 這是什麼意思詳細?

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

我如何得到一個什麼樣的細節出了問題嗎?我從回溯中知道這是一個memcpy行,導致它,但我怎麼看內存如何對齊?而我怎麼知道它應該如何對齊應該是

該項目是一個編譯器,它使用帶有OCaml垃圾回收器的Zend/PHP運行時的LLVM後端,因此存在很多可能出錯的情況。

我懷疑這線是問題的一部分:

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

其中caml_alloc分別在Zend的源代碼pemalloc

段錯誤發生在進行10'000個字符串連接時。這是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) 

任何提示讚賞。

編輯

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

編輯2

由於Valgrind的給了我此行

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

我想我試圖複製的東西,已經被釋放,這意味着我不會正確地告訴OCaml GC何時不再引用它。

+0

你能告訴我們'subsetphp_concat_function'嗎? –

+0

當您需要關於代碼中的錯誤的幫助時(有些人會認爲這不是Stackoverflow的原因),總是包含一些代碼(儘可能簡短)來產生錯誤。 – Thomash

+0

@ Mr.Llama補充。 –

回答

6

這個錯誤告訴你在memcpy期間發生了一些不好的事情,可能是像空指針或大小錯誤。

不要打擾__memcpy_sse2_unaligned,它是memcpy的實現細節。 memcpy有許多不同的實現,針對不同的情況進行了優化,並動態分派給給定上下文的最有效的實例。當sse2指令可用並且指針未被分配到16個字節邊界(sse2指令不能加載未對齊值)時,似乎可以使用這一點,這可能通過一次複製一個字節直到達到16字節邊界來完成,然後切換到快速路徑。

至於與LLVM鏈接的OCaml gc特定細節,您需要非常小心如何處理堆指針。由於您不知道您是使用gcroot機制還是使用新的狀態點,我會假設您使用的是gcroot。由於OCaml gc是一個移動收集器(從小堆移動到大堆,並在壓縮過程中移動),因此每個分配都可能會使指針無效。這意味着將堆分配值的字段訪問分解是通常不安全的。舉例來說,這是不安全的:

​​

函數調用可以做一些分配,這可能會引發壓實。

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

順便說一句,我甚至肯定的是gcroot機制能夠正確地處理移動GC(即LLVM不優化的東西它不該「噸)。

這樣usualy手段用OCaml的GC來使用gcroot並不是一個好主意,新的方法對於那種GC來說更好,但是你仍然需要小心,不要在函數調用或分配時訪問指針。與這種問題有關的東西:指針在某個時刻是有效的,然後一個值被移動了duri ng壓縮導致一些gc頁面未被使用,因此被釋放。