On 2017/11/4 15:24, Adrien Nader wrote:
Good morning,
I was looking at the changelog for OCaml 4.06 and noticed the following
entry:
- MPR#7638: in the Windows Mingw64 port, multithreaded programs
compiled to bytecode could crash when raising an exception from C
code. This looks like a Mingw64 issue, which we work around with GCC
builtins. (Xavier Leroy)
This leads to the following pages:
https://caml.inria.fr/mantis/view.php?id=7638
http://www.agardner.me/golang/windows/cgo/64-bit/setjmp/longjmp/2016/02/29/go-windows-setjmp-x86.html
https://sourceforge.net/p/mingw-w64/bugs/406/
Does anyone know if this issue has been fixed and if the bug report
should be closed, or if this has flown under the radar?
Thanks,
I presume this is caused by the x64-Windows-specific `longjmp()`
behavior. This reply is merely my presumption. I know nothing about Go
or Lua.
The Microsoft documentation (`longjump` in this link is NOT a typo):
<https://docs.microsoft.com/en-us/cpp/build/setjmp-longjump>
says on x64 Windows the `longjmp()` function unwinds the stack, which is
less common elsewhere. Hence, on Windows x64 a function must contain
stack unwind information, otherwise crash will happen when `longjmp` is
called inside it.
Steps to reproduce:
1. Create `test.c`:
```c
#include <setjmp.h>
#include <stdio.h>
jmp_buf buf;
int main(void){
if(setjmp(buf) == 0){
puts("about to jump...");
longjmp(buf, 1);
} else {
puts("returned from setjmp()");
}
}
```
2. Compile it to assembly using `gcc test.c -S -o test.s`:
```
.file "test.c"
.comm buf, 256, 5
.def __main; .scl 2; .type 32; .endef
.section .rdata,"dr"
.LC0:
.ascii "about to jump...\0"
.LC1:
.ascii "returned from setjmp()\0"
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
call __main
movq %rbp, %rax
movq %rax, %rdx
leaq buf(%rip), %rax
movq %rax, %rcx
call _setjmp
testl %eax, %eax
jne .L3
leaq .LC0(%rip), %rcx
call puts
movl $1, %edx
leaq buf(%rip), %rax
movq %rax, %rcx
call longjmp
.L3:
leaq .LC1(%rip), %rcx
call puts
movl $0, %eax
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (gcc-7-branch HEAD with MCF thread model, built
by LH_Mouse.) 7.2.1 20171027"
.def _setjmp; .scl 2; .type 32; .endef
.def puts; .scl 2; .type 32; .endef
.def longjmp; .scl 2; .type 32; .endef
```
3. Note those pseudo instructions that begin with `.seh_`. These
instructions set up unwind information for the `main()` function. If you
delete them, you get a crash after the first line of text is printed:
```
LH_Mouse@LH_Mouse-PC /e/Desktop
$ cat test.s | sed "/\\.seh_/d" | as - -o test.o && gcc test.o && "./a.exe"
about to jump...
LH_Mouse@LH_Mouse-PC /e/Desktop
$ echo $?
127
```
`__builtin_setjmp()` and `__builtin_longjmp()` are GCC-specific
implementation that preserves only a minimal set of registers. They
differ from those from MSVCRT that, like most other implementations,
they do not unwind the stack. Hence they do not require stack unwind
information and will not cause crashes in the example above.
--
Best regards,
LH_Mouse
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public