Random failures in compiled code

  • From: Igor Ehrlich <igor.a.ehrlich@xxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Mon, 4 Apr 2016 12:35:25 +0300

Dear all,

during the investigation of random core dumps in LuaJIT 2.0.4, I found an
issue that's present in both master and 2.1 branches, which may lead to
random failures with arbitrary symptoms on x86 and x86_64. The issue
affects x86 and x86_64 targets, GNU/Linux confirmed, other OSes are most
probably affected too. Such failures are extremely hard to reproduce, so
I'll just dump the results of the investigation below.

First of all, during the compilation of a trace emitter produces the
following mcode:

0xfa98b57: jne 0x1efbca7b
  # 0f 85 1e 3f 52 0f
0xfa98b5d: cmp DWORD PTR [rdx+0x274],0xfffffffb
  # 83 ba 74 02 00 00 fb

FTR, these are the last instruction of HREFK and the first instruction of
HLOAD with "str" output type. Everything works fine until the compiler
generates a side trace for this trace and starts patching the parent. The
function lj_asm_patchexit scans parent trace byte-by-byte and eventually
comes to the address 0xfa98b5c in attempt to find a six-byte side exit jcc
pattern. As you may see, this is not an address of any particular valid
instruction. The six-byte pattern here overlaps the last byte of jne and
five bytes of cmp, looking like "0f 83 ba 74 02 00". Patcher tries to
interpret this as a jcc instruction, and it __succeeds__, as "0f 83" works
for it as an opcode and 0x274ba is the __exact relative offset__ from
0xfa98b5c to the stub of the side exit being patched (plus-minus 6, hope
you get the idea).

As a result of this misinterpretation, bytes 0xfa98b5c through 0xfa98b5f
are patched with the offset to the newly created side trace, resulting in...

0xfa98b57:  jne 0x1efbca7b
  # 0f 85 1e 3f 52 0f
0xfa98b5d:  and DWORD PTR [rsi],0x1b
  # 83 26 1b
0xfa98b60:  rex.WX (bad)
  # 00
0xfa98b63:  sti
  # fb

...and the application segfaults on 0xfa98b5d. Actually, that's the point
where the investigation was started.

As it was said earlier, technically, you can get virtually any error here.
This might be a SIGSEGV, or SIGILL. If you are lucky enough to encounter
such an unlikely issue, you might even get no error with an unpredictable
outcome.

Best regards,
Igor A. Ehrlich

Other related posts: