diff options
author | Yao Qi <yao.qi@linaro.org> | 2017-04-10 14:39:41 +0100 |
---|---|---|
committer | Yao Qi <yao.qi@linaro.org> | 2017-04-10 14:39:41 +0100 |
commit | 803bdfe43083475c7df3db38dc96f4e20d05457d (patch) | |
tree | a07c0036f9ff54f9be271361b0e9260657541cff /gdb/gdbthread.h | |
parent | 8c25b49760b854d0b8451e8ecffeb9860fc41158 (diff) | |
download | fsf-binutils-gdb-803bdfe43083475c7df3db38dc96f4e20d05457d.zip fsf-binutils-gdb-803bdfe43083475c7df3db38dc96f4e20d05457d.tar.gz fsf-binutils-gdb-803bdfe43083475c7df3db38dc96f4e20d05457d.tar.bz2 |
Don't delete thread_info if refcount isn't zero
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 deleting thread_info object if it is
deletable, otherwise, mark it as exited (by set_thread_exited).
Function set_thread_exited is shared from delete_thread_1. This patch
also moves field "refcount" to private and methods incref and
decref. Additionally, we stop using "ptid_t" in
"struct current_thread_cleanup" to reference threads, instead we use
"thread_info" directly. Due to this change, we don't need
restore_current_thread_ptid_changed anymore.
gdb:
2017-04-10 Yao Qi <yao.qi@linaro.org>
PR gdb/19942
* gdbthread.h (thread_info::deletable): New method.
(thread_info::incref): New method.
(thread_info::decref): New method.
(thread_info::refcount): Move it to private.
* infrun.c (save_stop_context): Call inc_refcount.
(release_stop_context_cleanup): Likewise.
* thread.c (set_thread_exited): New function.
(init_thread_list): Delete "tp" only it is deletable, otherwise
call set_thread_exited.
(delete_thread_1): Call set_thread_exited.
(current_thread_cleanup) <inferior_pid>: Remove.
<thread>: New field.
(restore_current_thread_ptid_changed): Removed.
(do_restore_current_thread_cleanup): Adjust.
(restore_current_thread_cleanup_dtor): Don't call
find_thread_ptid.
(set_thread_refcount): Use dec_refcount.
(make_cleanup_restore_current_thread): Adjust.
(thread_apply_all_command): Call inc_refcount.
(_initialize_thread): Don't call
observer_attach_thread_ptid_changed.
Diffstat (limited to 'gdb/gdbthread.h')
-rw-r--r-- | gdb/gdbthread.h | 33 |
1 files changed, 28 insertions, 5 deletions
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index 9a16fe6..4cd7390 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -183,6 +183,27 @@ public: explicit thread_info (inferior *inf, ptid_t ptid); ~thread_info (); + bool deletable () const + { + /* If this is the current thread, or there's code out there that + relies on it existing (m_refcount > 0) we can't delete yet. */ + return (m_refcount == 0 && !ptid_equal (ptid, inferior_ptid)); + } + + /* Increase the refcount. */ + void incref () + { + gdb_assert (m_refcount >= 0); + m_refcount++; + } + + /* Decrease the refcount. */ + void decref () + { + m_refcount--; + gdb_assert (m_refcount >= 0); + } + struct thread_info *next = NULL; ptid_t ptid; /* "Actual process id"; In fact, this may be overloaded with @@ -254,11 +275,6 @@ public: but STATE will still be THREAD_RUNNING. */ enum thread_state state = THREAD_STOPPED; - /* If this is > 0, then it means there's code out there that relies - on this thread being listed. Don't delete it from the lists even - if we detect it exiting. */ - int refcount = 0; - /* State of GDB control of inferior thread execution. See `struct thread_control_state'. */ thread_control_state control {}; @@ -346,6 +362,13 @@ public: fields point to self. */ struct thread_info *step_over_prev = NULL; struct thread_info *step_over_next = NULL; + +private: + + /* If this is > 0, then it means there's code out there that relies + on this thread being listed. Don't delete it from the lists even + if we detect it exiting. */ + int m_refcount = 0; }; /* Create an empty thread list, or empty the existing one. */ |