Reg : gdb crash is seen while attaching a process to gdb.

Yao Qi qiyaoltc@gmail.com
Mon Mar 27 08:54:00 GMT 2017


RAJESH DASARI <raajeshdasari@gmail.com> writes:

> Thanks for your quick response . Could you please share those patches
> , I will recompile the gdb with the patches and test the changes.

Could you try the patch below on 7.12?  If the patch doesn't work,
please provide the GDB's stack backtrace on internal error.

-- 
Yao (齐尧)
From 0621d3b4c0c665defc2166ee6240dc85f909275a Mon Sep 17 00:00:00 2001
From: Yao Qi <yao.qi@linaro.org>
Date: Mon, 27 Mar 2017 09:42:38 +0100
Subject: [PATCH] Fix refcount of thread_info

I build GDB with asan, and run test case hook-stop.exp, and threadapply.exp,
I got the following asan error,

=================================================================^M
^[[1m^[[31m==2291==ERROR: AddressSanitizer: heap-use-after-free on address 0x6160000999c4 at pc 0x000000826022 bp 0x7ffd28a8ff70 sp 0x7ffd28a8ff60^M
^[[1m^[[0m^[[1m^[[34mREAD of size 4 at 0x6160000999c4 thread T0^[[1m^[[0m^M
    #0 0x826021 in release_stop_context_cleanup ../../binutils-gdb/gdb/infrun.c:8203^M
    #1 0x72798a in do_my_cleanups ../../binutils-gdb/gdb/common/cleanups.c:154^M
    #2 0x727a32 in do_cleanups(cleanup*) ../../binutils-gdb/gdb/common/cleanups.c:176^M
    #3 0x826895 in normal_stop() ../../binutils-gdb/gdb/infrun.c:8381^M
    #4 0x815208 in fetch_inferior_event(void*) ../../binutils-gdb/gdb/infrun.c:4011^M
    #5 0x868aca in inferior_event_handler(inferior_event_type, void*) ../../binutils-gdb/gdb/inf-loop.c:44^M
....
^[[1m^[[32m0x6160000999c4 is located 68 bytes inside of 568-byte region [0x616000099980,0x616000099bb8)^M
^[[1m^[[0m^[[1m^[[35mfreed by thread T0 here:^[[1m^[[0m^M
    #0 0x7fb0bc1312ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)^M
    #1 0xb8c62f in xfree(void*) ../../binutils-gdb/gdb/common/common-utils.c:100^M
    #2 0x83df67 in free_thread ../../binutils-gdb/gdb/thread.c:207^M
    #3 0x83dfd2 in init_thread_list() ../../binutils-gdb/gdb/thread.c:223^M
    #4 0x805494 in kill_command ../../binutils-gdb/gdb/infcmd.c:2595^M
....

Detaching from program: /home/yao.qi/SourceCode/gnu/build-with-asan/gdb/testsuite/outputs/gdb.threads/threadapply/threadapply, process 2399^M
=================================================================^M
^[[1m^[[31m==2387==ERROR: AddressSanitizer: heap-use-after-free on address 0x6160000a98c0 at pc 0x00000083fd28 bp 0x7ffd401c3110 sp 0x7ffd401c3100^M
^[[1m^[[0m^[[1m^[[34mREAD of size 4 at 0x6160000a98c0 thread T0^[[1m^[[0m^M
    #0 0x83fd27 in thread_alive ../../binutils-gdb/gdb/thread.c:741^M
    #1 0x844277 in thread_apply_all_command ../../binutils-gdb/gdb/thread.c:1804^M
....
^M
^[[1m^[[32m0x6160000a98c0 is located 64 bytes inside of 568-byte region [0x6160000a9880,0x6160000a9ab8)^M
^[[1m^[[0m^[[1m^[[35mfreed by thread T0 here:^[[1m^[[0m^M
    #0 0x7f59a7e322ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)^M
    #1 0xb8c62f in xfree(void*) ../../binutils-gdb/gdb/common/common-utils.c:100^M
    #2 0x83df67 in free_thread ../../binutils-gdb/gdb/thread.c:207^M
    #3 0x83dfd2 in init_thread_list() ../../binutils-gdb/gdb/thread.c:223^M

This patch fixes the issue by always checking refcount before decreasing it.
If it is zero already, free the thread_info.

gdb:

2017-03-27  Yao Qi  <yao.qi@linaro.org>

        PR gdb/19942
	* gdbthread.h (free_thread): Declare.
	* infrun.c (release_stop_context_cleanup): If refcount is zero
	call free_thread.
	* thread.c (free_thread): Remove "static".
	(init_thread_list): If refcount is zero, call free_thread.
	(restore_current_thread_cleanup_dtor): Likewise.
	(set_thread_refcount): Likewise.
---
 gdb/gdbthread.h |  3 +++
 gdb/infrun.c    |  7 ++++++-
 gdb/thread.c    | 21 +++++++++++++++++----
 3 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 455cfd8..f89c6e1 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -369,6 +369,9 @@ extern void delete_thread (ptid_t);
    exited, for example.  */
 extern void delete_thread_silent (ptid_t);
 
+/* Free TP.  */
+extern void free_thread (struct thread_info *tp);
+
 /* Delete a step_resume_breakpoint from the thread database.  */
 extern void delete_step_resume_breakpoint (struct thread_info *);
 
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 5125ede..13b74bd 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -8200,7 +8200,12 @@ release_stop_context_cleanup (void *arg)
   struct stop_context *sc = (struct stop_context *) arg;
 
   if (sc->thread != NULL)
-    sc->thread->refcount--;
+    {
+      if (sc->thread->refcount == 0)
+	free_thread (sc->thread);
+      else
+	sc->thread->refcount--;
+    }
   xfree (sc);
 }
 
diff --git a/gdb/thread.c b/gdb/thread.c
index 1e39ac4..36dc40f 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -192,7 +192,7 @@ clear_thread_inferior_resources (struct thread_info *tp)
   thread_cancel_execution_command (tp);
 }
 
-static void
+void
 free_thread (struct thread_info *tp)
 {
   if (tp->priv)
@@ -220,7 +220,10 @@ init_thread_list (void)
   for (tp = thread_list; tp; tp = tpnext)
     {
       tpnext = tp->next;
-      free_thread (tp);
+      if (tp->refcount == 0)
+	free_thread (tp);
+      else
+	tp->refcount--;
     }
 
   thread_list = NULL;
@@ -1612,7 +1615,12 @@ restore_current_thread_cleanup_dtor (void *arg)
 
   tp = find_thread_ptid (old->inferior_ptid);
   if (tp)
-    tp->refcount--;
+    {
+      if (tp->refcount == 0)
+	free_thread (tp);
+      else
+	tp->refcount--;
+    }
   inf = find_inferior_id (old->inf_id);
   if (inf != NULL)
     inf->removable = old->was_removable;
@@ -1629,7 +1637,12 @@ set_thread_refcount (void *data)
     = (struct thread_array_cleanup *) data;
 
   for (k = 0; k != ta_cleanup->count; k++)
-    ta_cleanup->tp_array[k]->refcount--;
+    {
+      if (ta_cleanup->tp_array[k]->refcount == 0)
+	free_thread (ta_cleanup->tp_array[k]);
+      else
+	ta_cleanup->tp_array[k]->refcount--;
+    }
 }
 
 struct cleanup *
-- 
1.9.1



More information about the Gdb mailing list