__memcpy_sse2_unaligned – 这是什么意思?

在处理我的编译器时,我遇到了这个错误:

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

我如何获得此处出现问题的详细信息? 我从回溯中知道它是一个记忆线导致它,但我如何看待内存是如何对齐的? 我怎么知道它应该如何对齐?

该项目是一个带有LLVM后端的编译器,使用Zend / PHP运行时和OCaml垃圾收集器,因此有很多问题可能出错。

我怀疑这条线是问题的一部分:

 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: memcpy@@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。

这个错误告诉你在memcpy期间发生了一些不好的事情,可能类似于空指针或大小错误。

不要打扰__memcpy_sse2_unaligned ,它是memcpy的一个实现细节。 memcpy有许多针对不同情况优化的不同实现,并动态调度到给定上下文的最有效的实现。 当sse2指令可用且指针未分配到16字节边界(sse2指令不能加载未对齐的值)时,似乎可以使用那个,这可能是通过一次复制一个字节直到达到16字节边界然后切换到快速的道路。

至于与LLVM链接的OCaml gc特定细节,您需要非常小心如何处理堆指针。 由于您没有告诉您是使用gcroot机制还是新的状态点,我假设您正在使用gcroot。

由于OCaml gc是一个移动收集器(从小堆移动到主堆,并在压缩期间移动),每个分配都可能使指针无效。 这意味着将对堆分配值的字段访问因素分解通常是不安全的。 例如,这是不安全的:

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

函数调用可以执行一些可能触发压缩的分配。

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

顺便说一句,我甚至不确定gcroot机制是否可以正确处理移动gc(llvm不会优化它不应该的东西)。

因此,通常意味着将gcroot与OCaml的GC一起使用并不是一个好主意。 新方法对于那种GC更好,但是您仍然需要注意不要跨函数调用或分配访问指针。

因此,您的错误可能与此类问题有关:指针在某些时候有效,然后在压缩期间移动了一个值,导致某些gc页面未被使用,因此被释放。