summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Faylor <me@cgf.cx>2008-02-27 17:16:46 +0000
committerChristopher Faylor <me@cgf.cx>2008-02-27 17:16:46 +0000
commit8ba248a94b612aa0c826204904ed5b1480397362 (patch)
treeaf9a90a456da6131d2a922f839c01ae53795e146
parentca504a0dee89cd4ca92db404601f3a5d0fdef497 (diff)
downloadcygnal-8ba248a94b612aa0c826204904ed5b1480397362.tar.gz
cygnal-8ba248a94b612aa0c826204904ed5b1480397362.tar.bz2
cygnal-8ba248a94b612aa0c826204904ed5b1480397362.zip
* cygtls.cc (_cygtls::handle_threadlist_exception): Make it clear that the
function never actually returns. * exceptions.cc (_cygtls::handle_exceptions): Jump out of function rather than returning to avoid meddling by previously installed exception handlers.
-rw-r--r--winsup/cygwin/ChangeLog8
-rw-r--r--winsup/cygwin/cygtls.cc4
-rw-r--r--winsup/cygwin/exceptions.cc16
3 files changed, 25 insertions, 3 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 428f73707..554e93efa 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,11 @@
+2008-02-27 Christopher Faylor <me+cygwin@cgf.cx>
+
+ * cygtls.cc (_cygtls::handle_threadlist_exception): Make it clear that
+ the function never actually returns.
+ * exceptions.cc (_cygtls::handle_exceptions): Jump out of function
+ rather than returning to avoid meddling by previously installed
+ exception handlers.
+
2008-02-25 Corinna Vinschen <corinna@vinschen.de>
* dcrt0.cc (initial_env): Only use local buffer "buf" if DEBUGGING is
diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc
index af2723e95..310f2e637 100644
--- a/winsup/cygwin/cygtls.cc
+++ b/winsup/cygwin/cygtls.cc
@@ -221,7 +221,7 @@ _cygtls::set_siginfo (sigpacket *pack)
infodata = pack->si;
}
-extern "C" DWORD __stdcall RtlUnwind (void *, void *, void *, DWORD);
+extern "C" DWORD __stdcall RtlUnwind (void *, void *, void *, DWORD) __attribute__ ((noreturn));
int
_cygtls::handle_threadlist_exception (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *c, void *)
{
@@ -248,7 +248,7 @@ _cygtls::handle_threadlist_exception (EXCEPTION_RECORD *e, exception_list *frame
cygheap->threadlist[threadlist_ix]->remove (INFINITE);
threadlist_ix = 0;
RtlUnwind (frame, threadlist_exception_return, e, 0);
- return 0;
+ /* Never returns */
}
/* Set up the exception handler for the current thread. The x86 uses segment
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 3c0080953..34defe51b 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -659,7 +659,21 @@ _cygtls::handle_exceptions (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT
sig_send (NULL, si, &me); // Signal myself
me.incyg--;
e->ExceptionFlags = 0;
- return 0;
+ /* The OS adds an exception list frame to the stack. It expects to be
+ able to remove this entry after the exception handler returned.
+ However, when unwinding to our frame, our frame becomes the uppermost
+ frame on the stack (%fs:0 points to frame). This way, our frame
+ is removed from the exception stack and just disappears. So, we can't
+ just return here or things will be screwed up by the helpful function
+ in (presumably) ntdll.dll.
+
+ So, instead, we will do the equivalent of a longjmp here and return
+ to the caller without visiting any of the helpful code installed prior
+ to this function. This should work ok, since a longjmp() out of here has
+ to work if linux signal semantics are to be maintained. */
+
+ SetThreadContext (GetCurrentThread (), in);
+ return 0; /* Never actually returns. This is just to keep gcc happy. */
}
/* Utilities to call a user supplied exception handler. */