Created attachment 11022 [details] code to reproduce the bug GDB version: 7.12.50 OS: Ubuntu 17.04 Kernel: 4.10.0-21-generic python: v3.5 Bug Description ====================================================================== I try to test a simple multi-thread program in C. Before the program launches, I add a break point using GDB python API in the function that would be called by all worker threads. Inside the break point, I add some code which would call a dummy function "bar()" in the target program. To prevent concurrency, I use "set scheduler-locking on/off" to wrap my function call. The problem is that at some point, when a new thread is created, the scheduler-locking is broken and 1st thread entering "bar()" would hang there and when the 2nd thread gets into "bar()", gdb crashes. After checking gdb database, this bug seems related with Bug 20291. I put the code to help reproduce the problem. Code ====================================================================== C code: ---------------------------------------------------------------------- #include <stdio.h> #include <stdlib.h> #include <pthread.h> struct thread_info { /* Used as argument to thread_start() */ pthread_t thread_id; /* ID returned by pthread_create() */ int thread_num; /* Application-defined thread # */ char *argv_string; /* From command-line argument */ }; /* some function that should report something to gdb */ int bar() { /* do nothing */ return 0; } void execute_task(int id) { printf("worker %d, execute task\n", id); } void *worker(void *arg) { int idx = 0; int rounds = 10; struct thread_info *tinfo = (struct thread_info *)arg; for (idx = 0; idx < rounds; idx++) { execute_task(tinfo->thread_num); } } void main() { int tnum = 3; int num_threads = tnum; void *res; struct thread_info *tinfo = calloc(num_threads, sizeof(struct thread_info)); for (tnum = 0; tnum < num_threads; tnum++) { tinfo[tnum].thread_num = tnum + 1; pthread_create(&tinfo[tnum].thread_id, NULL, &worker, &tinfo[tnum]); } for (tnum = 0; tnum < num_threads; tnum++) { pthread_join(tinfo[tnum].thread_id, &res); } } Note: this is a simple C program that create 3 worker thread, each of which is basically print and done. gdb python code: ---------------------------------------------------------------------- class IgnoreErrorsCommand (gdb.Command): """Execute a single command, ignoring all errors. Only one-line commands are supported. This is primarily useful in scripts.""" def __init__ (self): super (IgnoreErrorsCommand, self).__init__ ("ignore-errors", gdb.COMMAND_OBSCURE, # FIXME... gdb.COMPLETE_COMMAND) def invoke (self, arg, from_tty): try: gdb.execute (arg, from_tty) except: pass IgnoreErrorsCommand () class ReturnBreakpoint(gdb.Breakpoint): def stop (self): print("come to returnbreakpoint") tid = gdb.selected_thread().num print("thread id: %d"%tid) gdb.execute("call $myfunc(0)") gdb.write("done calling function\n") return False ReturnBreakpoint("*execute_task") class MyCmd (gdb.Function): """JIT Code Memory Permission Controller using Pkey.""" def __init__ (self): super (MyCmd, self).__init__ ("myfunc") def invoke (self, arg): print("++++++++++++++++++command execution begin+++++++++++++++") tid = gdb.selected_thread().num try: gdb.execute("set scheduler-locking on") gdb.execute("call bar()") gdb.execute("set scheduler-locking off") except: print("*****exception*****") print("++++++++++++++++++command execution done++++++++++++++++") return "done" MyCmd() gdbinit file: ---------------------------------------------------------------------- set logging on set pagination off set target-async 1 set non-stop on set breakpoint pending on set print thread-events on set confirm off handle 11 nopass source ./python_code.py b *0x0 ignore-errors r del 2 r gdb launch command: ---------------------------------------------------------------------- gdb -x gdbinit ../test Result: ====================================================================== GDB response: Reading symbols from ../test...done. Breakpoint 1 at 0x80b: file main.c, line 21. Breakpoint 2 at 0x0 No unwaited-for children left. [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". [New Thread 0x7ffff77f1700 (LWP 17090)] [New Thread 0x7ffff6ff0700 (LWP 17091)] come to returnbreakpoint thread id: 2 ++++++++++++++++++command execution begin+++++++++++++++ [New Thread 0x7ffff67ef700 (LWP 17092)] $1 = 0 ++++++++++++++++++command execution done++++++++++++++++ $2 = "done" done calling function come to returnbreakpoint thread id: 3 ++++++++++++++++++command execution begin+++++++++++++++ worker 1, execute task come to returnbreakpoint thread id: 4 ++++++++++++++++++command execution begin+++++++++++++++ come to returnbreakpoint thread id: 2 ++++++++++++++++++command execution begin+++++++++++++++ /build/gdb-sBS5Fz/gdb-7.12.50.20170314/gdb/infcall.c:1372: internal-error: value* call_function_by_hand_dummy(value*, int, value**, void (*)(void*, int), void*): ... should not be here A problem internal to GDB has been detected, further debugging may prove unreliable. This is a bug, please report it. For instructions, see: <http://www.gnu.org/software/gdb/bugs/>. ./debug.sh: line 8: 17083 Aborted (core dumped) gdb -x $1 --args ../test GDB core stacktrace: #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:58 58 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory. (gdb) bt #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:58 #1 0x00007f53de7e337a in __GI_abort () at abort.c:89 #2 0x00005575fc78bf66 in dump_core () at ./gdb/utils.c:465 #3 0x00005575fc78e70a in internal_vproblem(internal_problem *, const char *, int, const char *, typedef __va_list_tag __va_list_tag *) ( problem=problem@entry=0x5575fce031e0 <internal_error_problem>, file=<optimized out>, line=<optimized out>, fmt=<optimized out>, ap=ap@entry=0x7ffe6df0ae10) at ./gdb/utils.c:676 #4 0x00005575fc78e7db in internal_verror (file=<optimized out>, line=<optimized out>, fmt=<optimized out>, ap=ap@entry=0x7ffe6df0ae10) at ./gdb/utils.c:702 #5 0x00005575fc69ce1f in internal_error (file=file@entry=0x5575fc990e98 "/build/gdb-sBS5Fz/gdb-7.12.50.20170314/gdb/infcall.c", line=line@entry=1372, fmt=fmt@entry=0x5575fc96f843 "%s: %s") at ./gdb/common/errors.c:55 #6 0x00005575fc6d4239 in call_function_by_hand_dummy at ./gdb/infcall.c:1372 #7 0x00005575fc6d457a in call_function_by_hand (......) at ./gdb/infcall.c:677 #8 0x00005575fc6a158e in evaluate_subexp_standard (......) at ./gdb/eval.c:1750 #9 0x00005575fc64161d in evaluate_subexp_c (......) at ./gdb/c-lang.c:713 #10 0x00005575fc69d6dd in evaluate_expression (exp=exp@entry=0x5575fd66a100) at ./gdb/eval.c:143 #11 0x00005575fc723793 in print_command_1 (exp=<optimized out>, voidprint=0) at ./gdb/printcmd.c:1258 #12 0x00005575fc58c8f5 in cmd_func (cmd=0x5575fd06e150, args=0x7ffe6df0b525 "bar()", from_tty=0) at ./gdb/cli/cli-decode.c:1888 #13 0x00005575fc7860a3 in execute_command (p=<optimized out>, from_tty=from_tty@entry=0) at ./gdb/top.c:674 #14 0x00005575fc5cbfa0 in execute_gdb_command (self=<optimized out>, args=<optimized out>, kw=<optimized out>) at ./gdb/python/python.c:621 #15 0x00007f53df9b9299 in PyCFunction_Call () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0 #16 0x00007f53dfaea6f9 in PyEval_EvalFrameEx () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0 #17 0x00007f53dfbac084 in ?? () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0 #18 0x00007f53dfbac163 in PyEval_EvalCodeEx () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0 #19 0x00007f53dfa3f528 in ?? () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0 #20 0x00007f53dfb1b9f7 in PyObject_Call () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0 #21 0x00007f53dfb6792c in ?? () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0 #22 0x00007f53dfb1b9f7 in PyObject_Call () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0 #23 0x00005575fc5b738b in fnpy_call (gdbarch=<optimized out>, language=<optimized out>, cookie=0x7f53dd3a7048, argc=<optimized out>, argv=0x7ffe6df0b9d8) at ./gdb/python/py-function.c:82 #24 0x00005575fc6a15b3 in evaluate_subexp_standard (expect_type=expect_type@entry=0x0, exp=exp@entry=0x5575fd6493f0, pos=<optimized out>, noside=noside@entry=EVAL_NORMAL) at ./gdb/eval.c:1746 #25 0x00005575fc64161d in evaluate_subexp_c (expect_type=0x0, exp=0x5575fd6493f0, pos=0x7ffe6df0bc94, noside=EVAL_NORMAL) at ./gdb/c-lang.c:713 #26 0x00005575fc69d6dd in evaluate_expression (exp=exp@entry=0x5575fd6493f0) at ./gdb/eval.c:143 #27 0x00005575fc723793 in print_command_1 (exp=<optimized out>, voidprint=0) at ./gdb/printcmd.c:1258 #28 0x00005575fc58c8f5 in cmd_func (cmd=0x5575fd06e150, args=0x5575fd493c95 "$jitmemctrl(0, 1, 1)", from_tty=0) at ./gdb/cli/cli-decode.c:1888 #29 0x00005575fc7860a3 in execute_command (p=<optimized out>, from_tty=from_tty@entry=0) at ./gdb/top.c:674 #30 0x00005575fc5cbfa0 in execute_gdb_command (self=<optimized out>, args=<optimized out>, kw=<optimized out>) at ./gdb/python/python.c:621 #31 0x00007f53df9b9299 in PyCFunction_Call () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
Possible duplicate (or at least very closely related) bug 28911 has simpler repro instructions.
This is being fixed using a different bug, so picking that one as canonical. *** This bug has been marked as a duplicate of bug 28942 ***