|
From: <sv...@va...> - 2011-02-04 20:51:06
|
Author: weidendo
Date: 2011-02-04 20:50:58 +0000 (Fri, 04 Feb 2011)
New Revision: 11524
Log:
Fix bug 246152
When unwinding needs to be done because the stack pointer is reset
(e.g. by a longjmp), it makes no sense to interprete the control
flow change as call, but should be seen as a return.
This indirectly fixes bug 246152. Unwinding potentially changes the
exec state, which is unique for threads, but also for signal handlers.
E.g. this is true for a longjmp out of a signal handler. Exec state
changes modify members of struct CLG_(current_state), such as
CLG_(current_state).bbcc and CLG_(current_state).jmps_passed, which
are backed in CLG_(setup_bbcc)() by last_bbcc and passed, respectivly.
On a exec state change, these local vars go out of sync, and lead
to invalid data passed to CLG_(push_call_stack)() for handling a call,
which triggered data corruption, and the symptoms seen in bug 246152.
As in the given situation, there is no call anymore, there is no call
into CLG_(push_call_stack)(), and the corruption (or since last commit
the failed assertion) is not triggered any more.
Modified:
trunk/callgrind/bbcc.c
trunk/callgrind/callstack.c
trunk/callgrind/global.h
Modified: trunk/callgrind/bbcc.c
===================================================================
--- trunk/callgrind/bbcc.c 2011-02-04 19:55:25 UTC (rev 11523)
+++ trunk/callgrind/bbcc.c 2011-02-04 20:50:58 UTC (rev 11524)
@@ -741,7 +741,11 @@
}
}
else {
- CLG_(unwind_call_stack)(sp, 0);
+ Int unwind_count = CLG_(unwind_call_stack)(sp, 0);
+ if (unwind_count > 0) {
+ /* if unwinding was done, this actually is a return */
+ jmpkind = Ijk_Ret;
+ }
if (jmpkind == Ijk_Call) {
delayed_push = True;
Modified: trunk/callgrind/callstack.c
===================================================================
--- trunk/callgrind/callstack.c 2011-02-04 19:55:25 UTC (rev 11523)
+++ trunk/callgrind/callstack.c 2011-02-04 20:50:58 UTC (rev 11524)
@@ -394,11 +394,13 @@
}
-/* remove CallStack items to sync with current SP
+/* Unwind enough CallStack items to sync with current stack pointer.
+ * Returns the number of stack frames unwinded.
*/
-void CLG_(unwind_call_stack)(Addr sp, Int minpops)
+Int CLG_(unwind_call_stack)(Addr sp, Int minpops)
{
Int csp;
+ Int unwind_count = 0;
CLG_DEBUG(4,"+ unwind_call_stack(sp %#lx, minpops %d): frame %d\n",
sp, minpops, CLG_(current_call_stack).sp);
@@ -415,6 +417,7 @@
((top_ce->sp == sp) && minpops>0)) {
minpops--;
+ unwind_count++;
CLG_(pop_call_stack)();
csp=CLG_(current_call_stack).sp;
continue;
@@ -423,4 +426,5 @@
}
CLG_DEBUG(4,"- unwind_call_stack\n");
+ return unwind_count;
}
Modified: trunk/callgrind/global.h
===================================================================
--- trunk/callgrind/global.h 2011-02-04 19:55:25 UTC (rev 11523)
+++ trunk/callgrind/global.h 2011-02-04 20:50:58 UTC (rev 11524)
@@ -779,7 +779,7 @@
void CLG_(push_call_stack)(BBCC* from, UInt jmp, BBCC* to, Addr sp, Bool skip);
void CLG_(pop_call_stack)(void);
-void CLG_(unwind_call_stack)(Addr sp, Int);
+Int CLG_(unwind_call_stack)(Addr sp, Int);
/* from context.c */
void CLG_(init_fn_stack)(fn_stack*);
|