This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: LSDA unwind information is off by one (in __gcc_personality_v0)


On 10/20/2016 10:28 AM, Florian Weimer wrote:
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.
So the issue is the PC is expected to be pointing to the start of the next instruction after whatever threw the exception.

Thus the -1 to get back into the right region.

We've had to do similar hackery in gdb, memstomp and probably elsewhere to deal with this slightly undesirable situation.

Obviously if the PC value is actually pointing at the proper instruction, then the decrement is highly undesirable as it could put the adjusted PC into a different exception region.

Jeff


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]