We have a fun little glibc bug which causes pthread_cond_wait to write
out of bounds on i386:
https://sourceware.org/bugzilla/show_bug.cgi?id=20719
Root cause is this in libgcc/unwind-c.c:
130 int ip_before_insn = 0;
…
158 /* Parse the LSDA header. */
159 p = parse_lsda_header (context, language_specific_data, &info);
160 #ifdef HAVE_GETIPINFO
161 ip = _Unwind_GetIPInfo (context, &ip_before_insn);
162 #else
163 ip = _Unwind_GetIP (context);
164 #endif
165 if (! ip_before_insn)
166 --ip;
167 landing_pad = 0;
The PC decrement cannot be possibly meaningful on CISC architectures
with variable instruction lengths. I suspect it's an unintentional
leftover from the ia64 port.
I wonder how GCC itself copes with the decrement in
__gcc_personality_v0. This probably matters to Ada the most because it
supports asynchronous exceptions by default.
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with System.Machine_Code; use System.Machine_Code;
procedure Proc is
begin
Asm ("# BEFORE", Volatile => True);
declare
B : Unbounded_String;
begin
Asm ("# WITHIN", Volatile => True);
end;
Asm ("# AFTER", Volatile => True);
end Proc;
Looking at the assembly, there does not seem to be any adjustment for
the off-by-one, but the asynchronous exception handler can be safely
executed multiple times (it has an internal guard flag), so maybe this
never matters. This off-by-one only matters for the exit from exception
handling regions because at the entry, we always get a PC value which is
at least one greater than the initial label because on i386 and x86_64,
the PC coming in from the kernel points after the last executed instruction.
I guess my question is if this is all working as designed.
If the decrement is ever removed from the libgcc unwinder, we should add
a compensating NOP in the glibc code. Otherwise, we can just adjust the
unwind tables.
Florian