Your C/C code suddenly started failing with SIGILL (illegal instruction) signal?
@ziglang's zig cc compiler enables sanitizers by default. In x86-64, it sprays ud1 and ud2 instructions here and there, and those instructions are responsible for SIGILL.
To make my life easier when debugging those issues, I wrote a simple script to de-sanitize an executable:
$./failing
SIGILL: illegal instruction
PC=0x3725509 m=0 sigcode=2
$ xxd -p -c99999999 failing | sed -E 's/670fb940../9090909090/g' | xxd -p -r > fixed && chmod x fixed
$ ./fixed
PASS
What the script does is replacing the ud1 instruction and its parameters with nop instructions. Why does it work?
The way zig cc spits out those checks is as follows:
33b47ac: cmp $0x0,%rax ; test for UB
33b47b0: jne 33b47bb ; if ok, jump to 33b47bb
33b47b6: ud1 0x16(x),x ; trip SIGILL signal
33b47bb: mov -0x20(%rbp),%rax ; continue
, so the instruction pointer will "jump over" the instruction which triggers SIGILL signal if the condition is ok, but it will execute it if the condition failed. If we instead patch ud1 with nops:
33b47ac: cmp $0x0,%rax
33b47b0: jne 33b47bb
33b47b6: nop
33b47b7: nop
33b47b8: nop
33b47b9: nop
33b47ba: nop
33b47bb: mov -0x20(%rbp),%rax
... we just harmlessly slide through nops and continue operating normally, even if the condition failed.
This ops layout doesn't sound like a coincidence. Pretty sure it's compiled like that exactly for the purpose of being able to "turn off" SIGILL, but maybe it's just a fluke.
How to fix the issue properly? Actually fix the undefined behavior! Usually boils down to reading uninitialized variables or trying to cast unaligned memory to integers. Happy hacking!