[llvm-bugs] [Bug 45489] New: Stackcoloring and setjmp/longjmp can miscompile

via llvm-bugs llvm-bugs at lists.llvm.org
Thu Apr 9 15:20:50 PDT 2020


https://bugs.llvm.org/show_bug.cgi?id=45489

            Bug ID: 45489
           Summary: Stackcoloring and setjmp/longjmp can miscompile
           Product: new-bugs
           Version: trunk
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: new bugs
          Assignee: unassignedbugs at nondot.org
          Reporter: diogo.sampaio at arm.com
                CC: htmldeveloper at gmail.com, llvm-bugs at lists.llvm.org

Created attachment 23339
  --> https://bugs.llvm.org/attachment.cgi?id=23339&action=edit
C Source reproducer and log files

If I do understand the attached MIR dumps, there is a bug in Stackcoloring by
merging variables alive before and after the longjmp call.

The relevant part of the C++ code is this one:
signed int main(void) {
  {
    S37 P0;         <= This variable shares stack slot with S18 P1 way below.
Ps: The initialization gets inlined.
    jmp_buf jb1;
    if (!setjmp(jb1)) {
      bar(jb1, P0); <= The pointer is incremented by 72 due the copy. function
bar is has a noreturn attribute and it just calls longjmp.
    }
  }
  {
    char *V6 = (char *)alloca(128);
    __asm volatile("" : : "r"(V6));
  }

  {
    __attribute((aligned(16))) char V7[16];
    __asm volatile("" : : "r"(&V7[0]));
  }

  __asm volatile("" : : "r"(__builtin_return_address(0)));

  S18 P1; <= Although the initialization is inligned, it still writes to the
correct address, thanks to Local Stack Slot Allocation and that it does not
write to the beginning of the variable.
  jmp_buf jb2;
  if (!setjmp(jb2)) {
    foo(jb2, P1); <= When making the copy of P1, it decides that is is the same
slot of S37. When reading P1, it is 72 bytes misaligned and reads just trash.
foo also has attribute noreturn.
  }

  return 0;
}


But this is the overall idea of the issue:
>From what I see, Stackcoloring merges two local objects into a single slot.
Object S37 is alive before the call of longjmp and object S18 is alive after
calling longjmp. The fact that bar has attribute noreturn allows optimizations
to the copy of S18. Thus, the variable holding the pointer to the shared stack
pointer slot is incremented during the copy to call bar. Function bar calls
longjmp, but as such changes to the shared slot pointer are recorded in the
spilled stack, it's value is not restored with the longjmp call. After that,
the object pointer to access S37 is misaligned by the size of the S18. That can
only be detected because S18 initialization does not write to the beginning of
the struct, so it uses a different variable as pointer (defined by Local Stack
Slot Allocation), and it is not spilled.

The before and after MIR for Stackcoloring, Local Stack Slot Allocation and
greedy register allocation are attached.


Trigging this fault is quite complicated, my reproducer mixes lto and no-lto
compiled files. Source files and build script, assuming you have required
aarch64 libraries in place, are attached.


=== Obs:
Disabling inlining or Local Stack Slot Allocation as well removes the error,
but solely because it avoids spillings. The noreturn attribute in bar is
important, as it allows the compiler to increment the pointer of P0 when doing
a copy, as no further use of it is known.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20200409/a11602f6/attachment.html>


More information about the llvm-bugs mailing list