277 lines
5.9 KiB
C
277 lines
5.9 KiB
C
#include <ntddk.h>
|
|
|
|
#include "active.h"
|
|
#include "locktest.h"
|
|
|
|
#if LOCKTEST_ACTIVE
|
|
|
|
//
|
|
// Real implementation if the module is active
|
|
//
|
|
|
|
VOID DeadlockPositiveTest (
|
|
PVOID NotUsed
|
|
)
|
|
{
|
|
DbgPrint ("Buggy: not implemented \n");
|
|
}
|
|
|
|
|
|
VOID DeadlockNegativeTest (
|
|
PVOID NotUsed
|
|
)
|
|
{
|
|
DbgPrint ("Buggy: not implemented \n");
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////// Stress test
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
StressLockHierarchy (
|
|
ULONG NumberOfIterations,
|
|
ULONG NumberOfResources,
|
|
ULONG Probability,
|
|
ULONG Seed,
|
|
BOOLEAN InjectDeadlocks
|
|
);
|
|
|
|
NTSYSAPI // ntifs
|
|
ULONG // ntifs
|
|
NTAPI // ntifs
|
|
RtlRandom ( // ntifs
|
|
PULONG Seed // ntifs
|
|
); // ntifs
|
|
|
|
|
|
ULONG InjectDeadlocks;
|
|
|
|
VOID
|
|
DeadlockStressTest (
|
|
PVOID NotUsed
|
|
)
|
|
{
|
|
StressLockHierarchy (128,
|
|
64,
|
|
20,
|
|
0,
|
|
InjectDeadlocks ? TRUE : FALSE);
|
|
}
|
|
|
|
#define LOCK_ACQUIRED 0x0001
|
|
#define LOCK_DELETED 0x0002
|
|
#define LOCK_RANDOM 0x0004
|
|
|
|
ULONG Finish;
|
|
|
|
VOID
|
|
StressLockHierarchy (
|
|
ULONG NumberOfIterations,
|
|
ULONG NumberOfResources,
|
|
ULONG Probability,
|
|
ULONG Seed,
|
|
BOOLEAN InjectDeadlocks
|
|
)
|
|
{
|
|
PFAST_MUTEX * Locks;
|
|
PULONG Flags;
|
|
ULONG I, J, K, Ri;
|
|
BOOLEAN ShouldAcquire;
|
|
BOOLEAN ShouldDelete;
|
|
|
|
Locks = NULL;
|
|
Flags = NULL;
|
|
|
|
Locks = (PFAST_MUTEX *) ExAllocatePool (NonPagedPool, NumberOfResources * sizeof (PFAST_MUTEX));
|
|
|
|
if (! Locks) {
|
|
goto Exit;
|
|
}
|
|
|
|
Flags = (PULONG) ExAllocatePool (NonPagedPool, NumberOfResources * sizeof (ULONG));
|
|
|
|
if (! Flags) {
|
|
goto Exit;
|
|
}
|
|
|
|
RtlZeroMemory (Locks, NumberOfResources * sizeof (PFAST_MUTEX));
|
|
RtlZeroMemory (Flags, NumberOfResources * sizeof (ULONG));
|
|
|
|
for (I = 0; I < NumberOfResources; I += 1) {
|
|
|
|
Locks[I] = ExAllocatePool (NonPagedPool, sizeof (FAST_MUTEX));
|
|
|
|
if (! (Locks[I])) {
|
|
goto Exit;
|
|
}
|
|
|
|
ExInitializeFastMutex (Locks[I]);
|
|
}
|
|
|
|
DbgPrint ("Starting test iterations ... \n");
|
|
|
|
KeEnterCriticalRegion ();
|
|
|
|
for (I = 0; I < NumberOfIterations; I += 1) {
|
|
|
|
BOOLEAN DeadlockInjected = FALSE;
|
|
|
|
if (InjectDeadlocks) {
|
|
|
|
Ri = RtlRandom(&Seed) % NumberOfResources;
|
|
|
|
if (! (Flags[Ri] & LOCK_DELETED)) {
|
|
|
|
ExAcquireFastMutexUnsafe (Locks[Ri]);
|
|
Flags[Ri] |= LOCK_ACQUIRED;
|
|
Flags[Ri] |= LOCK_RANDOM;
|
|
DeadlockInjected = TRUE;
|
|
}
|
|
}
|
|
|
|
for (J = 0; J < NumberOfResources; J += 1) {
|
|
|
|
if (Finish) {
|
|
return;
|
|
}
|
|
|
|
if ((Flags[J] & LOCK_DELETED)) {
|
|
DbgPrint (".");
|
|
continue;
|
|
}
|
|
|
|
if ((Flags[J] & LOCK_RANDOM)) {
|
|
DbgPrint ("*");
|
|
continue;
|
|
}
|
|
|
|
ShouldDelete = ((RtlRandom(&Seed) % 1000) < 10) ? TRUE : FALSE;
|
|
|
|
if (ShouldDelete) {
|
|
|
|
DbgPrint ("D");
|
|
|
|
// mark block in a special way so verifier version of ExFreePool
|
|
// will know we are deleting a resource.
|
|
|
|
*((PULONG)(Locks[J])) = 0xABCDDCBA;
|
|
ExFreePool (Locks[J]);
|
|
Locks[J] = NULL;
|
|
Flags[J] |= LOCK_DELETED;
|
|
}
|
|
|
|
if ((Flags[J] & LOCK_DELETED)) {
|
|
continue;
|
|
}
|
|
|
|
ShouldAcquire = ((RtlRandom(&Seed) % 100) < Probability) ? TRUE : FALSE;
|
|
|
|
if (ShouldAcquire) {
|
|
|
|
DbgPrint ("A");
|
|
ExAcquireFastMutexUnsafe (Locks[J]);
|
|
Flags[J] |= LOCK_ACQUIRED;
|
|
}
|
|
else {
|
|
DbgPrint ("-");
|
|
}
|
|
}
|
|
|
|
for (J = 0; J < NumberOfResources; J += 1) {
|
|
|
|
if (Finish) {
|
|
return;
|
|
}
|
|
|
|
// K = NumberOfResources - J - 1;
|
|
K = J; // release in reverse order
|
|
|
|
if ((Flags[K] & LOCK_DELETED)) {
|
|
continue;
|
|
}
|
|
|
|
if ((Flags[K] & LOCK_RANDOM)) {
|
|
continue;
|
|
}
|
|
|
|
if ((Flags[K] & LOCK_ACQUIRED)) {
|
|
// DbgPrint ("R");
|
|
ExReleaseFastMutexUnsafe (Locks[K]);
|
|
Flags[K] &= ~LOCK_ACQUIRED;
|
|
}
|
|
else {
|
|
// DbgPrint ("-");
|
|
}
|
|
}
|
|
|
|
if (DeadlockInjected) {
|
|
|
|
ExReleaseFastMutexUnsafe (Locks[Ri]);
|
|
Flags[Ri] &= ~LOCK_ACQUIRED;
|
|
Flags[Ri] &= ~LOCK_RANDOM;
|
|
}
|
|
|
|
// if (I && I % 100 == 0) {
|
|
DbgPrint ("\n");
|
|
// }
|
|
}
|
|
|
|
DbgPrint ("\n");
|
|
|
|
KeLeaveCriticalRegion ();
|
|
|
|
Exit:
|
|
|
|
for (I = 0; I < NumberOfResources; I += 1) {
|
|
if (Locks[I]) {
|
|
|
|
// mark block in a special way so verifier version of ExFreePool
|
|
// will know we are deleting a resource.
|
|
|
|
*((PULONG)(Locks[I])) = 0xABCDDCBA;
|
|
ExFreePool (Locks[I]);
|
|
}
|
|
}
|
|
|
|
if (Locks) {
|
|
ExFreePool (Locks);
|
|
}
|
|
|
|
if (Flags) {
|
|
ExFreePool (Flags);
|
|
}
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
//
|
|
// Dummy implementation if the module is inactive
|
|
//
|
|
|
|
VOID DeadlockPositiveTest (
|
|
PVOID NotUsed
|
|
)
|
|
{
|
|
DbgPrint ("Buggy: deadlock module is disabled \n");
|
|
}
|
|
|
|
|
|
VOID DeadlockNegativeTest (
|
|
PVOID NotUsed
|
|
)
|
|
{
|
|
DbgPrint ("Buggy: deadlock module is disabled \n");
|
|
}
|
|
|
|
VOID DeadlockStressTest (
|
|
PVOID NotUsed
|
|
)
|
|
{
|
|
DbgPrint ("Buggy: deadlock module is disabled \n");
|
|
}
|
|
|
|
#endif // #if !NEWSTUFF_ACTIVE
|
|
|