MCJIT longjmp failure on Win64 - was Invalid or unaligned stack exception on Windows

Now that I know what to look for it seems there are a number of posts
on this issue:

http://lists.cs.uiuc.edu/pipermail/llvmdev/2014-October/078332.html

I am changing the subject so that more people can find this topic.

Re your suggestion to use my own longjmp/setjmp - do you mean I should
use the LLVM intrinsics? But would they not call the Windows API
anyway?

I am also wondering if mingw gcc compilers have the same issue.

Thanks and Regards
Dibyendu

I think Paweł identified the problem. The frames on the stack between the
setjmp and longjmp must have valid unwind information, which is described
here:
https://msdn.microsoft.com/en-us/library/ft9x1kdx.aspx?f=255&MSPPError=-2147217396

In particular, it has this line about JITed code:
“For dynamically generated functions [JIT compilers], the runtime to
support these functions must either use RtlInstallFunctionTableCallback or
RtlAddFunctionTable to provide this information to the operating system.
Failure to do so will result in unreliable exception handling and debugging
of processes.”

LLVM does not contain any references to these functions, so I must conclude
that unwinding through LLVM JITed frames on Win64 is not supported. Sorry.
:frowning:

Now that I know what to look for it seems there are a number of posts
on this issue:

http://lists.cs.uiuc.edu/pipermail/llvmdev/2014-October/078332.html

I am changing the subject so that more people can find this topic.

Re your suggestion to use my own longjmp/setjmp - do you mean I should
use the LLVM intrinsics? But would they not call the Windows API
anyway?

I’m not sure what your requirements are. Can you specify why do you need longjmp?

The issue is your jump from longjmp call to setjmp location is crossing functions on callstack that were created by MCJIT. Those functions do not have proper stack unwinding information required by longjmp. The callstack looks like:

setjmp, MSVC/C++
other code, LLVM MCJIT
longjmp, MSVC/C++

Your solutions are:

  1. Pull longjmp call from C++ to LLVM IR. LLVM has a convenient intrinsic for that: llvm.longjmp. That solution is a bit fragile as that intrinsic will be lowered to C standard lib call, but if I remember correctly it worked for me. Windows might have 3 different implementation of longjmp: debug and release versions for C++ and C, maybe one of them is less fussy.
  2. Pull both longjmp and setjmp to LLVM IR. In that case you can switch from full-featured versions powered by standard library to lightweight builtin versions powered by LLVM (llvm.eh.sjlj.longjmp). Much better portability.
    In that second case, setting up llvm.eh.sjlj.setjmp correctly is a bit tricky. You need to place some data (as stack pointer) in the jump buffer manually. See http://lists.cs.uiuc.edu/pipermail/llvmdev/2015-February/081961.html

I am also wondering if mingw gcc compilers have the same issue.

MinGW has its own implementation of setjmp/longjmp. Its longjmp do not do C++ stack unwinding of course.

  • Paweł

I'm not sure what your requirements are. Can you specify why do you need
longjmp?

Lua uses setjmp/longjmp to implement exception handling. It is the Lua
infrastructure code that is making these calls.
A JIT compiled function does not directly call either - but may call a
Lua C function that then invokes longjmp.
As the Lua code is written in C - I do not need C++ stack unwinding.

The issue is your jump from longjmp call to setjmp location is crossing
functions on callstack that were created by MCJIT. Those functions do not
have proper stack unwinding information required by longjmp. The callstack
looks like:

setjmp, MSVC/C++
other code, LLVM MCJIT
longjmp, MSVC/C++

Your solutions are:

Pull longjmp call from C++ to LLVM IR. LLVM has a convenient intrinsic for
that: llvm.longjmp. That solution is a bit fragile as that intrinsic will be
lowered to C standard lib call, but if I remember correctly it worked for
me. Windows might have 3 different implementation of longjmp: debug and
release versions for C++ and C, maybe one of them is less fussy.
Pull both longjmp and setjmp to LLVM IR. In that case you can switch from
full-featured versions powered by standard library to lightweight builtin
versions powered by LLVM (llvm.eh.sjlj.longjmp). Much better portability.
In that second case, setting up llvm.eh.sjlj.setjmp correctly is a bit
tricky. You need to place some data (as stack pointer) in the jump buffer
manually. See
http://lists.cs.uiuc.edu/pipermail/llvmdev/2015-February/081961.html

I am also wondering if mingw gcc compilers have the same issue.

MinGW has its own implementation of setjmp/longjmp. Its longjmp do not do
C++ stack unwinding of course.

So the easiest option seems to be to compile using MingW ... I do not
need C++ stack unwinding so that should be fine.
I will also look at the built-ins - I can provide a JIT compiled
wrapper that can be invoked by the Lua C functions.

Many thanks for pointing me to this issue as I was wasting a lot of
time trying to figure out if there was a bug in my code that was
corrupting the stack.

Thanks and Regards
Dibyendu