Problem: __try1 will fail "mysteriously" (consistently, reproducably, but not according to any immediately obvious pattern) if optimisations are turned on.
Looking at the disassembly shows that in these cases of failure, instructions were reordered, thus if an exception occurred too soon after __try1, it would sometimes only install the SEH handler after the application had already crashed.
Fix: add a "memory" clobber as compiler barrier to __try1 (and probably it's a good idea to add one to __except1 too).
#define __try1(pHandler) \ __asm__ ("pushl %0;pushl %%fs:0;movl %%esp,%%fs:0;" : : "g" (pHandler) : "memory");
Assigning to Chris for follow up.
I need a sample test program attached to this issue. Thomas can you supply it?
No test program to display the issue.
I'm reopening this. I don't understand why it should have been closed as "invalid", because the OP has a very valid point; the inline assembly modifies memory behind the compiler's back, without offering even the slightest hint that it intends to do so. In fact, I would go further, and add not only the memory clobber constraint, but also explicitly add the "volatile" attribute; (it should be implied anyway, because there are no output parameters specified, but I prefer to make it explicitly obvious).
And yes,
__except1
also writes to memory behind the compiler's back, so it wouldn't just be a good idea to add a memory clobber constraint to it too -- it really should be considered as a mandatory requirement.It's actually much, much worse than just a missing memory clobber attribute; so bad, in fact, that I wonder did it ever work? It's certainly been FUBAR since GCC-3.4.5, if not before. The problem is not so much that it modifies memory behind the compiler's back, but that it modifies the stack pointer, in a manner which is entirely beyond GCC's comprehension. Here's an illustration, (compiled with GCC-3.4.5, after adding the memory clobber attribute -- adding
__volatile__
makes no difference -- and replacing embedded semicolons by"\n\t"
, within the inline assembly code, to yield more legible intermediate assembly output):Notice the two
popl
instructions, immediately following the first/APP.../NOAPP
block, (which corresponds to the__try1(bar)
statement). These are emitted by GCC, presumably with the (too late) intention to clear the argument pushed for the precedingcall _puts
; what they actually do is delete the exception handler reference frame we thought we'd just installed. This happens because__try1(bar)
changed the stack pointer when GCC wasn't looking, so it doesn't know it's undoing the effect of the inline assembly code; unfortunately, adding a stack pointer clobber doesn't mitigate this.So, it's broken for GCC-3.4.5 already; it gets (possibly) even worse for later versions of GCC. Here's what the same code looks like, with GCC-5.3.0:
Now, the destructive stack pointer adjustment after the
__try1(bar)
code has disappeared, but the compiler is still overwriting the exception handler frame, (by themovl %eax, 4(%esp)
andmovl %eax, (%esp)
instructions). Furthermore, the references the the auto variables,a
andb
, are now computed relative to%esp
,(the
leal 24(%esp), %eax
andleal 28(%esp), %eax
instructions respectively), where GCC-3.4.5 had used references based on%ebp
; these%esp
references are off by eight bytes, because the compiler doesn't comprehend the change in the stack pointer, within the__try1(bar)
code, and once again, specifying a stack pointer clobber has no mitigating effect.So, the current implementation is utterly broken, in a manner which will vector exceptions to trashed code addresses, so anything (possibly very bad) could happen, when an exception is thrown. I'm wondering if it's worth trying to fix this, or should
<excpt.h>
just disappear without trace?Last edit: Keith Marshall 2016-06-20
While simply pushing an exception handler frame on to the stack is doomed to failure, having GCC manage the reservation via
alloca()
, (actually__builtin_alloca()
) should be safe, and appears to work. Hence, I committed [fc36f6].Related
Commit: [fc36f6]