简体   繁体   English

__memcpy_sse2_unaligned - 这是什么意思?

[英]__memcpy_sse2_unaligned - what does this mean in detail?

While working on my compiler I got this error: 在处理我的编译器时,我遇到了这个错误:

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

How do I get details of what went wrong here? 如何获取此处出现问题的详细信息? I know from the backtrace it's a memcpy line that causes it, but how do I see how the memory is aligned? 我从backtrace中知道它是一个memcpy行导致它,但我如何看待内存是如何对齐的? And how do I know how it should be aligned? 我怎么知道它应该如何对齐?

The project is a compiler with an LLVM back-end using the Zend/PHP runtime with the OCaml garbage collector, so there's is a lot of things that can go wrong. 该项目是一个带有LLVM后端的编译器,使用Zend / PHP运行时和OCaml垃圾收集器,因此有很多问题可能出错。

I suspect this line being part of the problem: 我怀疑这一行是问题的一部分:

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

where caml_alloc were pemalloc in the Zend source-code. 其中caml_alloc是Zend源代码中的pemalloc

The segfault happens when doing 10'000 string concatenations. 在执行10,000个字符串连接时会发生段错误。 This is the output from valgrind: 这是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)

Any tips appreciated. 任何提示赞赏。

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 : 编辑2

Since valgrind gives me this line 因为valgrind给了我这条线

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

I guess I'm trying to copy something that has already been freed, meaning that I don't tell the OCaml GC correctly when something is no longer referenced. 我想我正在尝试复制已经被释放的东西,这意味着当不再引用某些东西时我没有正确地告诉OCaml GC。

This errors tells you that something bad happen during memcpy, probably something like a null pointer or error in the sizes. 这个错误告诉你在memcpy期间发生了一些不好的事情,可能类似于空指针或大小错误。

Don't bother with __memcpy_sse2_unaligned , it is an implementation detail of memcpy. 不要打扰__memcpy_sse2_unaligned ,它是memcpy的一个实现细节。 memcpy has a lot of different implementation optimized for the different cases and dispatch dynamically to the most efficient one given the context. memcpy有很多针对不同情况优化的不同实现,并动态调度到给定上下文的最有效的实现。 That one seems to be used when sse2 instructions are available and pointers are not alligned to 16 bytes boundaries (sse2 instructions cannot load unaligned values), which is probably done by copying one byte at a time until a 16 byte boundary is reached then switching to the fast path. 当sse2指令可用且指针未分配到16字节边界(sse2指令不能加载未对齐的值)时,似乎可以使用那个,这可能是通过一次复制一个字节直到达到16字节边界然后切换到快速的道路。

As for the OCaml gc specific details linked with LLVM, you need to be quite carefull to how you handle heap pointers. 至于与LLVM链接的OCaml gc特定细节,您需要非常小心如何处理堆指针。 As you don't tell whether you are using the gcroot mechanism or the new statepoints, I will suppose you are using gcroot. 由于您没有告诉您是使用gcroot机制还是新状态点,我假设您正在使用gcroot。

Since the OCaml gc is a moving collector (moving from minor heap to major heap, and moving during compaction) every allocation can potentially invalidate a pointer. 由于OCaml gc是一个移动收集器(从小堆移动到主堆,并在压缩期间移动),每个分配都可能使指针无效。 That means that it is usualy unsafe to factorise field access to heap allocated values. 这意味着将对堆分配值的字段访问因素分解通常是不安全的。 For instance this is unsafe: 例如,这是不安全的:

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

the function call could do some allocations that could trigger a compaction. 函数调用可以执行一些可能触发压缩的分配。

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

By the way, I'm not even certain that the gcroot mechanism can correctly handle moving gc (that llvm doesn't optimize things it shouldn"t). 顺便说一句,我甚至不确定gcroot机制是否可以正确处理移动gc(llvm不会优化它不应该的东西)。

So that usualy means that it's not a good idea to use gcroot with OCaml's GC. 因此,通常意味着将gcroot与OCaml的GC一起使用并不是一个好主意。 The new way is better for that kind of GC, but you still need to be carefull not to access pointer across function calls or allocations. 对于那种GC,新方法更好,但是您仍然需要注意不要跨函数调用或分配访问指针。

So your error may be something linked to that kind of problem: the pointer was valid at some point, then a value was moved during compaction that resulted in some gc page being unused, hence freed. 因此,您的错误可能与此类问题有关:指针在某些时候有效,然后在压缩期间移动了一个值,导致某些gc页面未被使用,因此被释放。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM