aboutsummaryrefslogtreecommitdiff
path: root/gdb/thread.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2015-03-24 21:01:29 +0000
committerPedro Alves <palves@redhat.com>2015-03-24 21:01:29 +0000
commita25d8bf9c5b2c9d3671f4508c9132485c65c3773 (patch)
treede5201dccc9dd45be87b0de32760d744f5c2a838 /gdb/thread.c
parent8d00121477371cfd1596118af062fe6ff4e263b7 (diff)
downloadgdb-a25d8bf9c5b2c9d3671f4508c9132485c65c3773.zip
gdb-a25d8bf9c5b2c9d3671f4508c9132485c65c3773.tar.gz
gdb-a25d8bf9c5b2c9d3671f4508c9132485c65c3773.tar.bz2
Fix "thread apply all" with exited threads
I noticed that "thread apply all" sometimes crashes. The problem is that thread_apply_all_command doesn take exited threads into account, and we qsort and then walk more elements than there really ever were put in the array. Valgrind shows: The current thread <Thread ID 3> has terminated. See `help thread'. (gdb) thread apply all p 1 Thread 1 (Thread 0x7ffff7fc2740 (LWP 29579)): $1 = 1 ==29576== Use of uninitialised value of size 8 ==29576== at 0x639CA8: set_thread_refcount (thread.c:1337) ==29576== by 0x5C2C7B: do_my_cleanups (cleanups.c:155) ==29576== by 0x5C2CE8: do_cleanups (cleanups.c:177) ==29576== by 0x63A191: thread_apply_all_command (thread.c:1477) ==29576== by 0x50374D: do_cfunc (cli-decode.c:105) ==29576== by 0x506865: cmd_func (cli-decode.c:1893) ==29576== by 0x7562CB: execute_command (top.c:476) ==29576== by 0x647DA4: command_handler (event-top.c:494) ==29576== by 0x648367: command_line_handler (event-top.c:692) ==29576== by 0x7BF7C9: rl_callback_read_char (callback.c:220) ==29576== by 0x64784C: rl_callback_read_char_wrapper (event-top.c:171) ==29576== by 0x647CB5: stdin_event_handler (event-top.c:432) ==29576== ... This can happen easily today as linux-nat.c/linux-thread-db.c are forgetting to purge non-current exited threads. But even with that fixed, we can always do "thread apply all" with an exited thread selected, which won't be deleted until the user switches to another thread. That's what the test added by this commit exercises. Tested on x86_64 Fedora 20. gdb/ChangeLog: 2015-03-24 Pedro Alves <palves@redhat.com> * thread.c (thread_apply_all_command): Take exited threads into account. gdb/testsuite/ChangeLog: 2015-03-24 Pedro Alves <palves@redhat.com> * gdb.threads/no-unwaited-for-left.exp: Test "thread apply all".
Diffstat (limited to 'gdb/thread.c')
-rw-r--r--gdb/thread.c15
1 files changed, 10 insertions, 5 deletions
diff --git a/gdb/thread.c b/gdb/thread.c
index 01eb2ba..ec398f5 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1434,9 +1434,10 @@ thread_apply_all_command (char *cmd, int from_tty)
execute_command. */
saved_cmd = xstrdup (cmd);
make_cleanup (xfree, saved_cmd);
- tc = thread_count ();
- if (tc)
+ /* Note this includes exited threads. */
+ tc = thread_count ();
+ if (tc != 0)
{
struct thread_info **tp_array;
struct thread_info *tp;
@@ -1446,8 +1447,6 @@ thread_apply_all_command (char *cmd, int from_tty)
command. */
tp_array = xmalloc (sizeof (struct thread_info *) * tc);
make_cleanup (xfree, tp_array);
- ta_cleanup.tp_array = tp_array;
- ta_cleanup.count = tc;
ALL_NON_EXITED_THREADS (tp)
{
@@ -1455,9 +1454,15 @@ thread_apply_all_command (char *cmd, int from_tty)
tp->refcount++;
i++;
}
+ /* Because we skipped exited threads, we may end up with fewer
+ threads in the array than the total count of threads. */
+ gdb_assert (i <= tc);
- qsort (tp_array, i, sizeof (*tp_array), tp_array_compar);
+ if (i != 0)
+ qsort (tp_array, i, sizeof (*tp_array), tp_array_compar);
+ ta_cleanup.tp_array = tp_array;
+ ta_cleanup.count = i;
make_cleanup (set_thread_refcount, &ta_cleanup);
for (k = 0; k != i; k++)