[FYI] Avoid crash in print_ada_task_info

Message ID 20191122221438.25273-1-tromey@adacore.com
State New
Headers show
Series
  • [FYI] Avoid crash in print_ada_task_info
Related show

Commit Message

Tom Tromey Nov. 22, 2019, 10:14 p.m.
In MI mode, print_ada_task_info can crash in find_thread_ptid when
trying to print an Ada task that is no longer alive.  This patch
avoids the problem by checking for this case.

Because this is Ada-specific, and because Joel approved it internally,
I am checking it in.

gdb/ChangeLog
2019-11-22  Tom Tromey  <tromey@adacore.com>

	* ada-tasks.c (ada_task_is_alive): Make parameter const.
	(print_ada_task_info): Don't try to fetch thread id if task is not
	alive.

gdb/gdbserver/ChangeLog
2019-11-22  Tom Tromey  <tromey@adacore.com>

	* gdb.ada/tasks.exp: Add -ada-task-info regression test.
	* gdb.ada/tasks/foo.adb: Add another stopping location.

Change-Id: If25eae6507eebb7537eb8adbcbaa1fc1eec88f5c
---
 gdb/ChangeLog                       |  6 ++++++
 gdb/ada-tasks.c                     | 13 ++++++++-----
 gdb/gdbserver/ChangeLog             |  5 +++++
 gdb/testsuite/gdb.ada/tasks.exp     |  8 +++++++-
 gdb/testsuite/gdb.ada/tasks/foo.adb |  3 +++
 5 files changed, 29 insertions(+), 6 deletions(-)

-- 
2.20.1

Patch

diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c
index 110a710a5ff..67aa0c79889 100644
--- a/gdb/ada-tasks.c
+++ b/gdb/ada-tasks.c
@@ -347,7 +347,7 @@  valid_task_id (int task_num)
    task state.  */
 
 static int
-ada_task_is_alive (struct ada_task_info *task_info)
+ada_task_is_alive (const struct ada_task_info *task_info)
 {
   return (task_info->state != Terminated);
 }
@@ -1127,14 +1127,17 @@  print_ada_task_info (struct ui_out *uiout,
       /* Print the associated Thread ID.  */
       if (uiout->is_mi_like_p ())
         {
-	  thread_info *thread = find_thread_ptid (task_info->ptid);
+	  thread_info *thread = (ada_task_is_alive (task_info)
+				 ? find_thread_ptid (task_info->ptid)
+				 : nullptr);
 
 	  if (thread != NULL)
 	    uiout->field_signed ("thread-id", thread->global_num);
 	  else
-	    /* This should never happen unless there is a bug somewhere,
-	       but be resilient when that happens.  */
-	    uiout->field_skip ("thread-id");
+	    {
+	      /* This can happen if the thread is no longer alive.  */
+	      uiout->field_skip ("thread-id");
+	    }
 	}
 
       /* Print the ID of the parent task.  */
diff --git a/gdb/testsuite/gdb.ada/tasks.exp b/gdb/testsuite/gdb.ada/tasks.exp
index 46a53fe76c4..021e902f7b0 100644
--- a/gdb/testsuite/gdb.ada/tasks.exp
+++ b/gdb/testsuite/gdb.ada/tasks.exp
@@ -82,4 +82,10 @@  gdb_test "info tasks" \
 # Now, resume the execution and make sure that GDB does not stop when
 # task 4 hits the breakpoint. Continuing thus results in our program
 # running to completion.
-gdb_continue_to_end "" continue 1
+set bp_location [gdb_get_line_number "STOP_HERE_2" ${testdir}/foo.adb]
+gdb_breakpoint foo.adb:$bp_location
+gdb_continue_to_breakpoint second ".*foo.adb:$bp_location.*null; -- STOP_HERE_2"
+
+# A regression test for a crash caused by trying to find the thread
+# for a terminated task.
+gdb_test "interpreter-exec mi \"-ada-task-info\"" ".*"
diff --git a/gdb/testsuite/gdb.ada/tasks/foo.adb b/gdb/testsuite/gdb.ada/tasks/foo.adb
index f95fed4f4ca..9fc43b07c94 100644
--- a/gdb/testsuite/gdb.ada/tasks/foo.adb
+++ b/gdb/testsuite/gdb.ada/tasks/foo.adb
@@ -65,4 +65,7 @@  begin
    for J in Task_List'Range loop
       Task_List (J).Finalize;
    end loop;
+
+   null; -- STOP_HERE_2
+
 end Foo;