[PATCH 2/2] wineserver: Fixed bug #7286, waiting thread is last thread referencing a change notification object.

Misha Koshelev mk144210 at bcm.tmc.edu
Sat Feb 3 13:29:01 CST 2007


This is the second patch of my patchset. I made my two patches into a
patchset, one that adds a conformance test to tickle bug #7286, and the 
other to fix the bug. The first encloses the code that crashes
wineserver with the line "wineserver: object.c:274: release_object:
Assertion `obj->refcount' failed" in an if (0) { } statement so that
other tests can run. The second patch undoes this enclosure. This occurs
on wine 0.9.22,0.9.29,0.9.30, and git when a waiting thread is the last
one that references a ChangeNotification handle and is waiting on it. In
this case, end_wait tries to destroy the changenotification object, and
dir_destroy in turn tries to queue a user APC to the thread. If no user
APCs are already waiting for the thread, it tries to call end_wait
again, which references the same thread->wait object as its caller
end_wait function and thus runs into a problem releasing an object which
has a refcount of zero. This problem is present when running the Vector
NTI software on wine. Thanks for everybody's help with this.

Changelog:

	* wineserver: Fixed bug #7286, waiting thread is last thread
                      referencing a change notification object.
          Disallows recursive calls to end_wait for the same thread.

-------------- next part --------------
From f3efeecad551e03ce5d1e513b74c91e2277dcba8 Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Sat, 3 Feb 2007 13:17:24 -0600
Subject: wineserver: Fixed bug #7286, waiting thread is last thread referencing a change notification object.
            Disallows recursive calls to end_wait for the same thread.
---
 dlls/kernel32/tests/change.c |    6 ++----
 server/thread.c              |    7 +++++++
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/dlls/kernel32/tests/change.c b/dlls/kernel32/tests/change.c
index fdcaa34..f31bdcf 100644
--- a/dlls/kernel32/tests/change.c
+++ b/dlls/kernel32/tests/change.c
@@ -354,10 +354,8 @@ static void test_ffcnMultipleThreads()
      * process awakening, which causes an APC to be sent to the process from
      * within the end_wait function. This crashes Wine GIT as of 2/3/7 and
      * 0.9.22, 0.9.29, 0.9.30. Works fine on Windows XP. */
-    if (0) {
-      status = WaitForMultipleObjects(2, handles, FALSE, 5000); 
-      ok(status == WAIT_OBJECT_0 || status == WAIT_OBJECT_0+1, "WaitForMultipleObjects status %d error %d\n", status, GetLastError());
-    }
+    status = WaitForMultipleObjects(2, handles, FALSE, 5000); 
+    ok(status == WAIT_OBJECT_0 || status == WAIT_OBJECT_0+1, "WaitForMultipleObjects status %d error %d\n", status, GetLastError());
     ok(GetExitCodeThread(handles[1], &exitcode), "Could not retrieve thread exit code\n");
 
     /* Clean up */
diff --git a/server/thread.c b/server/thread.c
index b4a16cd..b477364 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -58,6 +58,8 @@ struct thread_wait
     struct thread          *thread;     /* owner thread */
     int                     count;      /* count of objects */
     int                     flags;
+    int                     waking;     /* whether we are currently waking this
+					 * thread */
     void                   *cookie;     /* magic cookie to return to client */
     struct timeval          timeout;
     struct timeout_user    *user;
@@ -447,6 +449,7 @@ static void end_wait( struct thread *thr
     int i;
 
     assert( wait );
+    thread->wait->waking = 1;
     for (i = 0, entry = wait->queues; i < wait->count; i++, entry++)
         entry->obj->ops->remove_queue( entry->obj, entry );
     if (wait->user) remove_timeout_user( wait->user );
@@ -467,6 +470,7 @@ static int wait_on( int count, struct ob
     wait->count   = count;
     wait->flags   = flags;
     wait->user    = NULL;
+    wait->waking  = 0;
     current->wait = wait;
     if (flags & SELECT_TIMEOUT)
     {
@@ -495,6 +499,9 @@ static int check_wait( struct thread *th
     struct thread_wait *wait = thread->wait;
     struct wait_queue_entry *entry = wait->queues;
 
+    /* If we are already waking this thread, no need to wake it again */
+    if (wait->waking) return -1;
+
     /* Suspended threads may not acquire locks, but they can run system APCs */
     if (thread->process->suspend + thread->suspend > 0)
     {
-- 
1.4.1



More information about the wine-patches mailing list