Module: wine Branch: master Commit: 14206495e301e0cb8e1b1d878a2baf7470daf96b URL: http://source.winehq.org/git/wine.git/?a=commit;h=14206495e301e0cb8e1b1d878a...
Author: Jacek Caban jacek@codeweavers.com Date: Mon Mar 6 12:51:22 2017 +0100
ntdll: Don't modify LockCount in RtlLeaveCriticalSection if section is not acquired.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Sebastian Lackner sebastian@fds-team.de Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/ntdll/critsection.c | 6 ++++- dlls/ntdll/tests/rtl.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/critsection.c b/dlls/ntdll/critsection.c index e2eb364..e405b08 100644 --- a/dlls/ntdll/critsection.c +++ b/dlls/ntdll/critsection.c @@ -665,7 +665,11 @@ BOOL WINAPI RtlIsCriticalSectionLockedByThread( RTL_CRITICAL_SECTION *crit ) */ NTSTATUS WINAPI RtlLeaveCriticalSection( RTL_CRITICAL_SECTION *crit ) { - if (--crit->RecursionCount) interlocked_dec( &crit->LockCount ); + if (--crit->RecursionCount) + { + if (crit->RecursionCount > 0) interlocked_dec( &crit->LockCount ); + else ERR( "section %p is not acquired\n", crit ); + } else { crit->OwningThread = 0; diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index 43c26bd..b18cccf 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -2094,6 +2094,65 @@ static void test_RtlInitializeCriticalSectionEx(void) RtlDeleteCriticalSection(&cs); }
+static void test_RtlLeaveCriticalSection(void) +{ + RTL_CRITICAL_SECTION cs; + NTSTATUS status; + + if (!pRtlInitializeCriticalSectionEx) + return; /* Skip winxp */ + + status = RtlInitializeCriticalSection(&cs); + ok(!status, "RtlInitializeCriticalSection failed: %x\n", status); + + status = RtlEnterCriticalSection(&cs); + ok(!status, "RtlEnterCriticalSection failed: %x\n", status); + todo_wine + ok(cs.LockCount == -2, "expected LockCount == -2, got %d\n", cs.LockCount); + ok(cs.RecursionCount == 1, "expected RecursionCount == 1, got %d\n", cs.RecursionCount); + ok(cs.OwningThread == ULongToHandle(GetCurrentThreadId()), "unexpected OwningThread\n"); + + status = RtlLeaveCriticalSection(&cs); + ok(!status, "RtlLeaveCriticalSection failed: %x\n", status); + ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount); + ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount); + ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread); + + /* + * Trying to leave a section that wasn't acquired modifies RecusionCount to an invalid value, + * but doesn't modify LockCount so that an attempt to enter the section later will work. + */ + status = RtlLeaveCriticalSection(&cs); + ok(!status, "RtlLeaveCriticalSection failed: %x\n", status); + ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount); + ok(cs.RecursionCount == -1, "expected RecursionCount == -1, got %d\n", cs.RecursionCount); + ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread); + + /* and again */ + status = RtlLeaveCriticalSection(&cs); + ok(!status, "RtlLeaveCriticalSection failed: %x\n", status); + ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount); + ok(cs.RecursionCount == -2, "expected RecursionCount == -2, got %d\n", cs.RecursionCount); + ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread); + + /* entering section fixes RecursionCount */ + status = RtlEnterCriticalSection(&cs); + ok(!status, "RtlEnterCriticalSection failed: %x\n", status); + todo_wine + ok(cs.LockCount == -2, "expected LockCount == -2, got %d\n", cs.LockCount); + ok(cs.RecursionCount == 1, "expected RecursionCount == 1, got %d\n", cs.RecursionCount); + ok(cs.OwningThread == ULongToHandle(GetCurrentThreadId()), "unexpected OwningThread\n"); + + status = RtlLeaveCriticalSection(&cs); + ok(!status, "RtlLeaveCriticalSection failed: %x\n", status); + ok(cs.LockCount == -1, "expected LockCount == -1, got %d\n", cs.LockCount); + ok(cs.RecursionCount == 0, "expected RecursionCount == 0, got %d\n", cs.RecursionCount); + ok(!cs.OwningThread, "unexpected OwningThread %p\n", cs.OwningThread); + + status = RtlDeleteCriticalSection(&cs); + ok(!status, "RtlDeleteCriticalSection failed: %x\n", status); +} + START_TEST(rtl) { InitFunctionPtrs(); @@ -2125,4 +2184,5 @@ START_TEST(rtl) test_RtlDecompressBuffer(); test_RtlIsCriticalSectionLocked(); test_RtlInitializeCriticalSectionEx(); + test_RtlLeaveCriticalSection(); }