Workaround crashes from stale frame_info pointer (BZ 804256).

This commit is contained in:
Jan Kratochvil 2012-04-04 23:36:28 +02:00
parent 47a8f2fb72
commit eeab48e583
1 changed files with 16 additions and 110 deletions

View File

@ -33,9 +33,11 @@ gdb/
* progspace.c (switch_to_program_space_and_thread): Try not to call
switch_to_thread.
--- a/gdb/progspace.c
+++ b/gdb/progspace.c
@@ -481,17 +481,28 @@ save_current_space_and_thread (void)
Index: gdb-7.3.50.20110722/gdb/progspace.c
===================================================================
--- gdb-7.3.50.20110722.orig/gdb/progspace.c 2011-01-05 23:22:50.000000000 +0100
+++ gdb-7.3.50.20110722/gdb/progspace.c 2012-04-04 23:07:16.329038403 +0200
@@ -480,17 +480,36 @@ save_current_space_and_thread (void)
void
switch_to_program_space_and_thread (struct program_space *pspace)
{
@ -57,118 +59,22 @@ gdb/
if (tp != NULL)
{
- switch_to_thread (tp->ptid);
+ /* thread.c */
+ enum thread_state
+ {
+ THREAD_STOPPED,
+ THREAD_RUNNING,
+ THREAD_EXITED,
+ };
+
+ /* Prefer primarily thread not THREAD_EXITED and secondarily thread
+ not EXECUTING. */
+ if (current_tp == NULL
+ || (tp->state != THREAD_EXITED
+ && current_tp->state == THREAD_EXITED)
+ || (!tp->executing && current_tp->executing))
+ || (tp->state_ != THREAD_EXITED
+ && current_tp->state_ == THREAD_EXITED)
+ || (!tp->executing_ && current_tp->executing_))
+ switch_to_thread (tp->ptid);
+
/* Switching thread switches pspace implicitly. We're
done. */
return;
Reproducer with:
./gdb -nx ~/t/thread -ex 'b 24' -ex r -ex 'until 25'
Breakpoint 1, main () at /home/jkratoch/t/thread.c:24
24 v++;
Segmentation fault (core dumped)
#include <pthread.h>
#include <assert.h>
#include <unistd.h>
static int v;
static void *start (void *arg)
{
v++;
v++;
v++;
v++;
sleep (100);
return arg;
}
int main (void)
{
pthread_t thread1;
int i;
i = pthread_create (&thread1, NULL, start, NULL);
assert (i == 0);
v++;
v++;
v++;
v++;
i = pthread_join (thread1, NULL);
assert (i == 0);
return 0;
}
### --- a/gdb/frame.c
### +++ b/gdb/frame.c
### @@ -1522,12 +1522,30 @@ frame_observer_target_changed (struct target_ops *target)
### reinit_frame_cache ();
### }
###
### +typedef struct obstack obstack_s;
### +DEF_VEC_O (obstack_s);
### +static VEC (obstack_s) *frame_poison_vec;
### +
### +void frame_garbage_collection (void);
### +void
### +frame_garbage_collection (void)
### +{
### + struct obstack *obstack_p;
### + int ix;
### +
### + for (ix = 0; VEC_iterate (obstack_s, frame_poison_vec, ix, obstack_p); ix++)
### + obstack_free (obstack_p, 0);
### +
### + VEC_free (obstack_s, frame_poison_vec);
### + frame_poison_vec = NULL;
### +}
### +
### /* Flush the entire frame cache. */
###
### void
### reinit_frame_cache (void)
### {
### - struct frame_info *fi;
### + struct frame_info *fi, *fi_prev;
###
### /* Tear down all frame caches. */
### for (fi = current_frame; fi != NULL; fi = fi->prev)
### @@ -1538,8 +1556,14 @@ reinit_frame_cache (void)
### fi->base->unwind->dealloc_cache (fi, fi->base_cache);
### }
###
### + for (fi = current_frame; fi != NULL; fi = fi_prev)
### + {
### + fi_prev = fi->prev;
### + memset (fi, 0, sizeof (*fi));
### + }
### + VEC_safe_push (obstack_s, frame_poison_vec, &frame_cache_obstack);
### +
### /* Since we can't really be sure what the first object allocated was. */
### - obstack_free (&frame_cache_obstack, 0);
### obstack_init (&frame_cache_obstack);
###
### if (current_frame != NULL)
### --- a/gdb/top.c
### +++ b/gdb/top.c
### @@ -359,6 +359,11 @@ prepare_execute_command (void)
### if (non_stop)
### target_dcache_invalidate ();
###
### + {
### + extern void frame_garbage_collection (void);
### + frame_garbage_collection ();
### + }
### +
### return cleanup;
### }
###