[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