darwin: fix thinko (free thread port after threads are discovered).
authorTristan Gingold <tristan.gingold@adacore.com>
Wed, 9 Apr 2014 08:23:19 +0000 (10:23 +0200)
committerTristan Gingold <tristan.gingold@adacore.com>
Wed, 9 Apr 2014 08:23:19 +0000 (10:23 +0200)
Due to a thinko, a message could be not understood and ignored.  The result
was a dead-lock (gdb is waiting for an event that never happen).  The port
of the thread was deallocated before new threads are discovered.  As a
consequence, the origin of the message was unknown (instead of being
linked to the newly created thread).

gdb/
* darwin-nat.c (darwin_check_new_threads): Fix port leak, add
comments.
(darwin_decode_exception_message): Free port only after use.

gdb/ChangeLog
gdb/darwin-nat.c

index 889b5742d5d852684678a9fba85b7d48842ba25e..880c37a5ee56b6109782b9685d6f1313360aa055 100644 (file)
@@ -1,3 +1,9 @@
+2014-04-09  Tristan Gingold  <gingold@adacore.com>
+
+       * darwin-nat.c (darwin_check_new_threads): Fix port leak, add
+       comments.
+       (darwin_decode_exception_message): Free port only after use.
+
 2014-04-08  Pierre Langlois  <pierre.langlois@embecosm.com>
 
        * avr-tdep.c (struct gdbarch_tdep): Mention avrxmega in the comment.
index 6f9a64a5451b204cd50bb9f8492689eb18cb51ea..0ffa69aacdbf3a9c6ace1305575d9376d4f2c82b 100644 (file)
@@ -303,9 +303,18 @@ darwin_check_new_threads (struct inferior *inf)
          break;
       if (i == new_nbr)
        {
+         /* Deallocate ports.  */
+         for (i = 0; i < new_nbr; i++)
+           {
+             kret = mach_port_deallocate (mach_task_self (), thread_list[i]);
+             MACH_CHECK_ERROR (kret);
+           }
+
+         /* Deallocate the buffer.  */
          kret = vm_deallocate (gdb_task, (vm_address_t) thread_list,
                                new_nbr * sizeof (int));
          MACH_CHECK_ERROR (kret);
+
          return;
        }
     }
@@ -331,8 +340,10 @@ darwin_check_new_threads (struct inferior *inf)
          new_ix++;
          old_ix++;
 
-         kret = mach_port_deallocate (gdb_task, old_id);
+         /* Deallocate the port.  */
+         kret = mach_port_deallocate (gdb_task, new_id);
          MACH_CHECK_ERROR (kret);
+
          continue;
        }
       if (new_ix < new_nbr && new_id == MACH_PORT_DEAD)
@@ -382,6 +393,7 @@ darwin_check_new_threads (struct inferior *inf)
     VEC_free (darwin_thread_t, darwin_inf->threads);
   darwin_inf->threads = thread_vec;
 
+  /* Deallocate the buffer.  */
   kret = vm_deallocate (gdb_task, (vm_address_t) thread_list,
                        new_nbr * sizeof (int));
   MACH_CHECK_ERROR (kret);
@@ -594,11 +606,10 @@ darwin_decode_exception_message (mach_msg_header_t *hdr,
   task_port = desc[1].name;
   thread_port = desc[0].name;
 
-  /* We got new rights to the task and the thread.  Get rid of them.  */
+  /* We got new rights to the task, get rid of it.  Do not get rid of thread
+     right, as we will need it to find the thread.  */
   kret = mach_port_deallocate (mach_task_self (), task_port);
   MACH_CHECK_ERROR (kret);
-  kret = mach_port_deallocate (mach_task_self (), thread_port);
-  MACH_CHECK_ERROR (kret);
 
   /* Find process by port.  */
   inf = darwin_find_inferior_by_task (task_port);
@@ -611,6 +622,10 @@ darwin_decode_exception_message (mach_msg_header_t *hdr,
       kern_return_t kret;
       mig_reply_error_t reply;
 
+      /* Free thread port (we don't know it).  */
+      kret = mach_port_deallocate (mach_task_self (), thread_port);
+      MACH_CHECK_ERROR (kret);
+
       darwin_encode_reply (&reply, hdr, KERN_SUCCESS);
 
       kret = mach_msg (&reply.Head, MACH_SEND_MSG | MACH_SEND_INTERRUPT,
@@ -627,6 +642,11 @@ darwin_decode_exception_message (mach_msg_header_t *hdr,
      message can be deallocated.  */
   darwin_check_new_threads (inf);
 
+  /* Free the thread port (as gdb knows the thread, it has already has a right
+     for it, so this just decrement a reference counter).  */
+  kret = mach_port_deallocate (mach_task_self (), thread_port);
+  MACH_CHECK_ERROR (kret);
+
   thread = darwin_find_thread (inf, thread_port);
   if (thread == NULL)
     return -1;