Description
For PowerPC ELF 32-bit targets, LLVM forgets to provide CFI like .cfi_offset cr2, -88
for fields cr2, cr3, cr4 in the condition register. Function calls must preserve cr2, cr3, cr4. Because the CFI is missing, an unwinder (like libunwind) can't restore cr2, cr3, cr4, when it unwinds a function call.
I found the bug after OpenBSD/macppc's clang 16.0.6 miscompiled gdb, when a C++ exception crashed gdb by not restoring cr2. I reproduced the bug in 19.0.0git with this example,
struct flip {
int *p;
flip(int *a): p(a) { if (p) *p = 1; }
~flip() { if (p) *p = 0; }
};
#define N __attribute__((noinline))
int i;
N void flip2(int *p) { flip f(p); throw 0; }
N void flip1(int *p) { flip f(p); flip2(&i); }
int main() { try { flip1(nullptr); } catch(int) {} }
I compiled it with clang++ -O2. The example is small enough to optimize out cr2; I added noinline
to keep cr2 in the code. The functions flip1 and flip2 each use cr2 to test some pointer p, which is null in flip1 and non-null in flip2. The C++ exception from throw 0
unwinds flip2 without restoring cr2, then runs the C++ destructor ~flip in flip1 with a wrong cr2, so if (p) *p = 0
crashes by writing to a null p.
I will soon add a pull request.