[PATCH 1/2] kernel32: Added conformance test to tickle bug #7286

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


This supersedes my previous patches. 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:

	* kernel32: Added conformance test to tickle bug #7286,
                    waiting thread is last thread referencing a change  
                    notification object.

-------------- next part --------------
From 394353523292dbb80916139ffb724bfb2e6404e3 Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Sat, 3 Feb 2007 13:14:11 -0600
Subject: kernel32: Added conformance test to tickle bug #7286,
          waiting thread is last thread referencing a change notification object.
---
 dlls/kernel32/tests/change.c |   52 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 52 insertions(+), 0 deletions(-)

diff --git a/dlls/kernel32/tests/change.c b/dlls/kernel32/tests/change.c
index bf7cdc1..fdcaa34 100644
--- a/dlls/kernel32/tests/change.c
+++ b/dlls/kernel32/tests/change.c
@@ -317,6 +317,54 @@ static void test_ffcn(void)
     ok( r == TRUE, "failed to remove dir\n");
 }
 
+/* this test concentrates on the wait behavior when multiple threads are
+ * waiting on a change notification handle. */
+static void test_ffcnMultipleThreads()
+{
+    LONG r;
+    DWORD filter, threadId, status, exitcode;
+    HANDLE handles[2];
+    char path[MAX_PATH];
+
+    r = GetTempPathA(MAX_PATH, path);
+    ok(r, "GetTempPathA error: %d\n", GetLastError());
+
+    lstrcatA(path, "ffcnTestMultipleThreads");
+
+    RemoveDirectoryA(path);
+
+    r = CreateDirectoryA(path, NULL);
+    ok(r, "CreateDirectoryA error: %d\n", GetLastError()); 
+
+    filter = FILE_NOTIFY_CHANGE_FILE_NAME;
+    filter |= FILE_NOTIFY_CHANGE_DIR_NAME;
+
+    handles[0] = FindFirstChangeNotificationA(path, FALSE, filter);
+    ok(handles[0] != INVALID_HANDLE_VALUE, "FindFirstChangeNotification error: %d\n", GetLastError());
+
+    /* Test behavior if a waiting thread holds the last reference to a change
+     * directory object with an empty wine user APC queue for this thread (bug #7286) */
+
+    /* Create our notification thread */
+    handles[1] = CreateThread(NULL, 0, NotificationThread, (LPVOID)handles[0],
+                              0, &threadId);
+    ok(handles[1] != NULL, "CreateThread error: %d\n", GetLastError());
+
+    /* This is the part that fails with bug #7286. Here refcount is 1 on 
+     * 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());
+    }
+    ok(GetExitCodeThread(handles[1], &exitcode), "Could not retrieve thread exit code\n");
+
+    /* Clean up */
+    r = RemoveDirectoryA( path );
+    ok( r == TRUE, "failed to remove dir\n");    
+}
+
 typedef BOOL (WINAPI *fnReadDirectoryChangesW)(HANDLE,LPVOID,DWORD,BOOL,DWORD,
                          LPDWORD,LPOVERLAPPED,LPOVERLAPPED_COMPLETION_ROUTINE);
 fnReadDirectoryChangesW pReadDirectoryChangesW;
@@ -708,6 +756,10 @@ START_TEST(change)
     pReadDirectoryChangesW = (fnReadDirectoryChangesW)
         GetProcAddress(hkernel32, "ReadDirectoryChangesW");
 
+    test_ffcnMultipleThreads();
+    /* The above function runs a test that must occur before FindCloseChangeNotification is run in the
+       current thread to preserve the emptiness of the wine user APC queue. To ensure this it should be 
+       placed first. */
     test_FindFirstChangeNotification();
     test_ffcn();
     test_readdirectorychanges();
-- 
1.4.1



More information about the wine-patches mailing list