PAGE_FAULT_IN_NONPAGED_AREA in driver

No matter what I do I seem to get PAGE_FAULT_IN_NONPAGED_AREA in my kernel driver. I’ve read everything I could about linked lists but I’m no closer to the solution.

Do I also need to do a memory copy of the handle (ProcessId) returned by PsSetLoadImageNotifyRoutine?
Is if (!pointer) the same as if (pointer == NULL)?
Any clues to why I get PAGE_FAULT_IN_NONPAGED_AREA?

BOOLEAN ListContainsProcess(PSINGLE_LIST_ENTRY listHead, HANDLE ProcessId)
{
	PSINGLE_LIST_ENTRY entry = listHead->Next;

	if (entry == NULL)
	{
		return false;
	}

	while (entry != listHead)
	{
		PPROCESS_LIST list = (PPROCESS_LIST)CONTAINING_RECORD(entry, PROCESS_LIST, LinkField);
		DbgPrint("Handle is %d", ProcessId);
		if (list->ProcessId == ProcessId) {
			return true;
		}
		entry = entry->Next;
	}
	return false;

}

VOID ImageCallback(
	IN PUNICODE_STRING FullImageName,
	IN HANDLE ProcessId,
	IN PIMAGE_INFO ImageInfo
)
{
	UNREFERENCED_PARAMETER(ImageInfo);

	PDEVICE_EXTENSION extension;
	//
	// Assign extension variable
	//
	extension = (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;

	if (ProcessId == NULL) {
		DbgPrint("ProcessID is NULL");
		return;
	}

	if (ListContainsProcess(&ProcessListSingleHead, ProcessId)) 
	{
		DbgPrint("Process found in process list\n");
	}
	else
	{
		UNICODE_STRING path = RTL_CONSTANT_STRING(L"\\System32\\app.exe");
		if (RtlxSuffixUnicodeString(&path, FullImageName, TRUE)) {
			DbgPrint("App started\n");

			PPROCESS_LIST list = (PPROCESS_LIST)ExAllocatePoolWithTag(NonPagedPool, sizeof(PROCESS_LIST), 1);
			if (!list)
			{
				DbgPrint("STATUS_INSUFFICIENT_RESOURCES");
				return;
			}

			list->ProcessId = ProcessId;

			PushEntryList(&ProcessListSingleHead, &(list->LinkField));
		}
	}

    ...
}

*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced.  This cannot be protected by try-except.
Typically the address is just plain bad or it is pointing at freed memory.
Arguments:
Arg1: fffffffffffffff8, memory referenced.
Arg2: 0000000000000000, value 0 = read operation, 1 = write operation.
Arg3: fffff8800c3ee7dc, If non-zero, the instruction address which referenced the bad memory
	address.
Arg4: 0000000000000000, (reserved)

Debugging Details:
------------------


KEY_VALUES_STRING: 1


STACKHASH_ANALYSIS: 1

TIMELINE_ANALYSIS: 1


DUMP_CLASS: 1

DUMP_QUALIFIER: 401

DUMP_TYPE:  1

BUGCHECK_P1: fffffffffffffff8

BUGCHECK_P2: 0

BUGCHECK_P3: fffff8800c3ee7dc

BUGCHECK_P4: 0

READ_ADDRESS:  fffffffffffffff8 

FAULTING_IP: 
Driver!ListContainsProcess+5c [main.cpp @ 228]
fffff880`0c3ee7dc 483908          cmp     qword ptr [rax],rcx

MM_INTERNAL_CODE:  0

DEFAULT_BUCKET_ID:  WIN7_DRIVER_FAULT

BUGCHECK_STR:  0x50

PROCESS_NAME:  taskhost.exe

CURRENT_IRQL:  0


TRAP_FRAME:  fffff880095754d0 -- (.trap 0xfffff880095754d0)
NOTE: The trap frame does not contain all registers.
Some register values may be zeroed or incorrect.
rax=fffffffffffffff8 rbx=0000000000000000 rcx=0000000000000d08
rdx=000000000000000e rsi=0000000000000000 rdi=0000000000000000
rip=fffff8800c3ee7dc rsp=fffff88009575660 rbp=fffff80003c760f0
 r8=0000000000000065  r9=0000000000000003 r10=0000000000000000
r11=fffff88009575280 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0         nv up ei ng nz na pe nc
Driver!ListContainsProcess+0x5c:
fffff880`0c3ee7dc 483908          cmp     qword ptr [rax],rcx ds:ffffffff`fffffff8=????????????????
Resetting default scope

LAST_CONTROL_TRANSFER:  from fffff80003bc8562 to fffff80003aeeba0

STACK_TEXT:  
fffff880`09575378 fffff800`03bc8562 : 00000000`00000050 ffffffff`fffffff8 00000000`00000000 fffff880`095754d0 : nt!KeBugCheckEx
fffff880`09575380 fffff800`03afac96 : 00000000`00000000 ffffffff`fffffff8 00000000`00000000 00000000`00000001 : nt!MmAccessFault+0x2322
fffff880`095754d0 fffff880`0c3ee7dc : fffff880`0c3eece0 00000000`00000d08 00000000`00000065 00000000`00000003 : nt!KiPageFault+0x356
fffff880`09575660 fffff880`0c3ee62d : fffff880`0c3f0098 00000000`00000d08 00000000`00000000 00000000`00000000 : Driver!ListContainsProcess+0x5c [main.cpp @ 228] 
fffff880`095756a0 fffff800`03d3a6f8 : fffffa80`0a398c18 00000000`00000d08 fffff880`09575858 00000000`00000000 : Driver!ImageCallback+0x4d [main.cpp @ 273] 
fffff880`09575700 fffff800`03e8d262 : fffffa80`0a398bc0 fffffa80`0bc46278 fffffa80`0a3a8a50 00000000`00000000 : nt!PsCallImageNotifyRoutines+0xdc
fffff880`09575760 fffff800`03d4fcc7 : fffffa80`0a3a8a10 fffffa80`0bc46060 fffff880`09575a10 fffff880`09575a08 : nt!MiMapViewOfImageSection+0x9b2
fffff880`095758b0 fffff800`03d5541d : ffffe6be`00000004 fffffa80`0bc46060 fffff880`09575a10 00000000`00000000 : nt!MiMapViewOfSection+0x367
fffff880`095759a0 fffff800`03afcbd3 : 00000000`00000404 fffffa80`0b9f7060 00000000`0291f148 00000000`0291f301 : nt!NtMapViewOfSection+0x2bd
fffff880`09575a70 00000000`77849b0a : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x13
00000000`0291f128 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : 0x77849b0a


THREAD_SHA1_HASH_MOD_FUNC:  9a8c01c8d3d816fc81b482c5ab85d8bc45900d22

THREAD_SHA1_HASH_MOD_FUNC_OFFSET:  a008a686f51c9886a95257dfb15374e4ddc4cfd7

THREAD_SHA1_HASH_MOD:  c792971b158a39e417c8371a54cd46baa3e9df9b

FOLLOWUP_IP: 
Driver!ListContainsProcess+5c [main.cpp @ 228]
fffff880`0c3ee7dc 483908          cmp     qword ptr [rax],rcx

FAULT_INSTR_CODE:  75083948

FAULTING_SOURCE_LINE_NUMBER:  228

FAULTING_SOURCE_CODE:  
   224: 	while (entry != listHead)
   225: 	{
   226: 		PPROCESS_LIST list = (PPROCESS_LIST)CONTAINING_RECORD(entry, PROCESS_LIST, LinkField);
   227: 		DbgPrint("Handle is %d", ProcessId);
>  228: 		if (list->ProcessId == ProcessId) {
   229: 			return true;
   230: 		}
   231: 		entry = entry->Next;
   232: 	}
   233: 	return false;


SYMBOL_STACK_INDEX:  3

SYMBOL_NAME:  Driver!ListContainsProcess+5c

Any clues to why I get PAGE_FAULT_IN_NONPAGED_AREA?

if (ListContainsProcess(&ProcessListSingleHead, ProcessId))
{
DbgPrint(“Process found in process list\n”);
}

Well, you don’t show us ‘ProcessListSingleHead’ declaration in your code, but it seems to be an uniitialised variable with a random and undefined value. You are passing its address to ListContainsProcess() function, which treats its value as a valid pointer. Look at the line below

PSINGLE_LIST_ENTRY entry = listHead->Next;

Once you have passed the address of unitialised variable to a function, ‘entry’ points to the middle of nowhere at the moment. Therefore, you are lucky enough to crash the very first time you try to access an address that it points to. If you were not so lucky and ‘entry’ was pointing to a random but valid address, you would end up with memory corruption, i.e.finding a bug would not be as easy as it is now…

Anton Bassov

@anton_bassov said:

Any clues to why I get PAGE_FAULT_IN_NONPAGED_AREA?

if (ListContainsProcess(&ProcessListSingleHead, ProcessId))
{
DbgPrint(“Process found in process list\n”);
}

Well, you don’t show us ‘ProcessListSingleHead’ declaration in your code, but it seems to be an uniitialised variable with a random and undefined value. You are passing its address to ListContainsProcess() function, which treats its value as a valid pointer. Look at the line below

PSINGLE_LIST_ENTRY entry = listHead->Next;

Once you have passed the address of unitialised variable to a function, ‘entry’ points to the middle of nowhere at the moment. Therefore, you are lucky enough to crash the very first time you try to access an address that it points to. If you were not so lucky and ‘entry’ was pointing to a random but valid address, you would end up with memory corruption, i.e.finding a bug would not be as easy as it is now…

Anton Bassov

According to MSDN ProcessListSingleHead.Next = NULL; should be enough to initialize the linked list? Did I miss something?

typedef struct _ProcessList
{
	HANDLE ProcessId;
	SINGLE_LIST_ENTRY LinkField;
	SINGLE_LIST_ENTRY DllListSingleHead;

} PROCESS_LIST, *PPROCESS_LIST;

SINGLE_LIST_ENTRY ProcessListSingleHead;

NTSTATUS DriverEntry(
	IN PDRIVER_OBJECT DriverObject,
	IN PUNICODE_STRING RegistryPath
)
{
    ...
	ProcessListSingleHead.Next = NULL;
    ...

According to MSDN ProcessListSingleHead.Next = NULL; should be enough to initialize the linked list?

ProcessListSingleHead.Next = NULL;

Well, you did not show us this part in your original post,did you…

Did I miss something?

Indeed…

What you are missing is that,in order to be in a position to help you, we have to see ALL your code, rather than just separate
fragments of it …

Anton Bassov

@anton_bassov said:
Indeed…

What you are missing is that,in order to be in a position to help you, we have to see ALL your code, rather than just separate
fragments of it …

Anton Bassov

Here we go.

#include <ntddk.h>
#include <ntstrsafe.h>

#define FILE_DEVICE_UNKNOWN             0x00000022
#define IOCTL_UNKNOWN_BASE              FILE_DEVICE_UNKNOWN
#define IOCTL_PROCOBSRV_ACTIVATE_MONITORING    \
	CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0800, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
#define IOCTL_PROCOBSRV_GET_IMAGEINFO    \
	CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0802, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)

void UnloadDriver(
	PDRIVER_OBJECT DriverObject
);
NTSTATUS DispatchCreateClose(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp
);
NTSTATUS DispatchIoctl(
	IN PDEVICE_OBJECT DeviceObject,
	IN PIRP Irp
);

//
// Structure for holding info about activating/deactivating the driver
//
typedef struct _ActivateInfo
{
	BOOLEAN  bActivated;
} ACTIVATE_INFO, *PACTIVATE_INFO;

//
// Structure for process callback information
//
typedef struct _ImageCallbackInfo
{
	WCHAR FullImageName[1024];
	HANDLE ProcessId;
} IMAGE_CALLBACK_INFO, *PIMAGE_CALLBACK_INFO;

typedef struct _ImageCallbackInfo2
{
	UNICODE_STRING FullImageName;
	HANDLE ProcessId;
	SINGLE_LIST_ENTRY LinkField;
} IMAGE_CALLBACK_INFO2, *PIMAGE_CALLBACK_INFO2;

typedef struct _DllList
{
	PUNICODE_STRING FullImageName;
	SINGLE_LIST_ENTRY LinkField;
} DLL_LIST, *PDLL_LIST;

typedef struct _ProcessList
{
	HANDLE ProcessId;
	SINGLE_LIST_ENTRY LinkField;
	SINGLE_LIST_ENTRY DllListSingleHead;

} PROCESS_LIST, *PPROCESS_LIST;

//
// Private storage for process retreiving 
//
typedef struct _DEVICE_EXTENSION
{
	PDEVICE_OBJECT DeviceObject;
	PKEVENT ProcessEvent;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

//
// Global variables
//
PDEVICE_OBJECT g_pDeviceObject;
ACTIVATE_INFO  g_ActivateInfo;

SINGLE_LIST_ENTRY SingleHead;

SINGLE_LIST_ENTRY ProcessListSingleHead;

//
// The main entry point of the driver module
//
extern "C"
NTSTATUS DriverEntry(
	IN PDRIVER_OBJECT DriverObject,
	IN PUNICODE_STRING RegistryPath
)
{
	UNREFERENCED_PARAMETER(DriverObject);
	UNREFERENCED_PARAMETER(RegistryPath);

	NTSTATUS                  ntStatus;
	UNICODE_STRING            uszDriverString;
	UNICODE_STRING            uszDeviceString;
	UNICODE_STRING            uszProcessEventString;
	PDEVICE_OBJECT            pDeviceObject;
	PDEVICE_EXTENSION         extension;
	HANDLE                    hProcessHandle;

	DbgPrint("DriverEntry called\n");

	SingleHead.Next = NULL;

	//    
	// Point uszDriverString at the driver name
	//
	RtlInitUnicodeString(&uszDriverString, L"\\Device\\ProcObsrv");
	//
	// Create and initialize device object
	//
	ntStatus = IoCreateDevice(
		DriverObject,
		sizeof(DEVICE_EXTENSION),
		&uszDriverString,
		FILE_DEVICE_UNKNOWN,
		0,
		FALSE,
		&pDeviceObject
	);
	if (ntStatus != STATUS_SUCCESS)
		return ntStatus;
	//
	// Assign extension variable
	//
	extension = (PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;
	//
	// Point uszDeviceString at the device name
	//
	RtlInitUnicodeString(&uszDeviceString, L"\\DosDevices\\ProcObsrv");
	//
	// Create symbolic link to the user-visible name
	//
	ntStatus = IoCreateSymbolicLink(&uszDeviceString, &uszDriverString);

	if (ntStatus != STATUS_SUCCESS)
	{
		//
		// Delete device object if not successful
		//
		IoDeleteDevice(pDeviceObject);
		return ntStatus;
	}

	ProcessListSingleHead.Next = NULL;

	//
	// Assign global pointer to the device object for use by the callback functions
	//
	g_pDeviceObject = pDeviceObject;
	//
	// Setup initial state
	//
	g_ActivateInfo.bActivated = FALSE;
	//
	// Load structure to point to IRP handlers
	//
	DriverObject->DriverUnload = UnloadDriver;
	DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreateClose;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchCreateClose;
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
	//
	// Create event for user-mode processes to monitor
	//
	RtlInitUnicodeString(
		&uszProcessEventString,
		L"\\BaseNamedObjects\\ProcObsrvProcessEvent"
	);
	extension->ProcessEvent = IoCreateNotificationEvent(
		&uszProcessEventString,
		&hProcessHandle
	);
	//
	// Clear it out
	//
	KeClearEvent(extension->ProcessEvent);
	//
	// Return success
	//
	return ntStatus;
}

//
// Create and close routine
//
NTSTATUS DispatchCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	UNREFERENCED_PARAMETER(DeviceObject);
	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 0;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

BOOLEAN
NTAPI
RtlxSuffixUnicodeString(
	_In_ PUNICODE_STRING String1,
	_In_ PUNICODE_STRING String2,
	_In_ BOOLEAN CaseInSensitive
)
{
	//
	// RtlSuffixUnicodeString is not exported by ntoskrnl until Win10.
	//

	return String2->Length >= String1->Length &&
		RtlCompareUnicodeStrings(String2->Buffer + (String2->Length - String1->Length) / sizeof(WCHAR),
			String1->Length / sizeof(WCHAR),
			String1->Buffer,
			String1->Length / sizeof(WCHAR),
			CaseInSensitive) == 0;

}

BOOLEAN ListContainsProcess(PSINGLE_LIST_ENTRY listHead, HANDLE ProcessId)
{
	PSINGLE_LIST_ENTRY entry = listHead->Next;

	if (entry == NULL)
	{
		return false;
	}

	while (entry != listHead)
	{
		PPROCESS_LIST list = (PPROCESS_LIST)CONTAINING_RECORD(entry, PROCESS_LIST, LinkField);
		DbgPrint("Handle is %d", ProcessId);
		if (list->ProcessId == ProcessId) {
			return true;
		}
		entry = entry->Next;
	}
	return false;

}

VOID ImageCallback(
	IN PUNICODE_STRING FullImageName,
	IN HANDLE ProcessId,
	IN PIMAGE_INFO ImageInfo
)
{
	UNREFERENCED_PARAMETER(ImageInfo);

	PDEVICE_EXTENSION extension;
	//
	// Assign extension variable
	//
	extension = (PDEVICE_EXTENSION)g_pDeviceObject->DeviceExtension;

	if (ProcessId == NULL) {
		DbgPrint("ProcessID is NULL");
		return;
	}

	if (ListContainsProcess(&ProcessListSingleHead, ProcessId)) 
	{
		DbgPrint("Process found in process list\n");
	}
	else
	{
		UNICODE_STRING path = RTL_CONSTANT_STRING(L"\\System32\\app.exe");
		if (RtlxSuffixUnicodeString(&path, FullImageName, TRUE)) {
			DbgPrint("App started\n");

			PPROCESS_LIST list = (PPROCESS_LIST)ExAllocatePoolWithTag(NonPagedPool, sizeof(PROCESS_LIST), 1);
			if (!list)
			{
				DbgPrint("STATUS_INSUFFICIENT_RESOURCES");
				return;
			}

			list->ProcessId = ProcessId;

			PushEntryList(&ProcessListSingleHead, &(list->LinkField));
		}
	}

    PIMAGE_CALLBACK_INFO2 info = (PIMAGE_CALLBACK_INFO2)ExAllocatePoolWithTag(NonPagedPool, sizeof(IMAGE_CALLBACK_INFO2), 1);
	if (info == NULL)
	{
		DbgPrint("STATUS_INSUFFICIENT_RESOURCES");
		return;
	}
    
	RtlInitUnicodeString(&info->FullImageName, FullImageName->Buffer);

	info->ProcessId = ProcessId;

	PushEntryList(&SingleHead, &(info->LinkField));

	KeSetEvent(extension->ProcessEvent, 0, FALSE);
	KeClearEvent(extension->ProcessEvent);
}
    //
    // The dispatch routine
    //
    NTSTATUS DispatchIoctl(
    	IN PDEVICE_OBJECT DeviceObject,
    	IN PIRP           Irp
    )
    {
    	NTSTATUS               ntStatus = STATUS_UNSUCCESSFUL;
    	PIO_STACK_LOCATION     irpStack = IoGetCurrentIrpStackLocation(Irp);
    	PDEVICE_EXTENSION      extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
    	PIMAGE_CALLBACK_INFO   pImageCallbackInfo;
    
    	UNREFERENCED_PARAMETER(extension);
    
    	//
    	// These IOCTL handlers are the set and get interfaces between
    	// the driver and the user mode app
    	//
    	switch (irpStack->Parameters.DeviceIoControl.IoControlCode)
    	{
    	case IOCTL_PROCOBSRV_ACTIVATE_MONITORING:
    	{
    		ntStatus = ActivateMonitoringHanlder(Irp);
    		break;
    	}
    
    	case IOCTL_PROCOBSRV_GET_IMAGEINFO:
    	{
    		if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >=
    			sizeof(IMAGE_CALLBACK_INFO))
    		{
    			pImageCallbackInfo = (PIMAGE_CALLBACK_INFO)Irp->AssociatedIrp.SystemBuffer;
    
    			PSINGLE_LIST_ENTRY SingleListEntry;
    			SingleListEntry = PopEntryList(&SingleHead);
    
    			if (SingleListEntry != NULL)
    			{
    				PIMAGE_CALLBACK_INFO2 info = (PIMAGE_CALLBACK_INFO2)CONTAINING_RECORD(SingleListEntry, IMAGE_CALLBACK_INFO2, LinkField);
    
    				if (&info->FullImageName != NULL)
    				{
    					if ((&info->FullImageName)->Length <= sizeof(pImageCallbackInfo->FullImageName))
    					{
    						RtlCopyMemory(pImageCallbackInfo->FullImageName, (&info->FullImageName)->Buffer, (&info->FullImageName)->Length);
    					}
    				}
    				else
    				{
    					DbgPrint("Condition &info->FullImageName == NULL");
    				}
    				pImageCallbackInfo->ProcessId = info->ProcessId;
    
    				ExFreePool(info);
    			}
    
    			ntStatus = STATUS_SUCCESS;
    		}
    		break;
    	}
    
    	default:
    		break;
    	}
    
    	Irp->IoStatus.Status = ntStatus;
    	//
    	// Set number of bytes to copy back to user-mode
    	//
    	if (ntStatus == STATUS_SUCCESS)
    		Irp->IoStatus.Information =
    		irpStack->Parameters.DeviceIoControl.OutputBufferLength;
    	else
    		Irp->IoStatus.Information = 0;
    
    	IoCompleteRequest(Irp, IO_NO_INCREMENT);
    	
    	return ntStatus;
    }
    
    //
    // Driver unload routine
    //
    void UnloadDriver(
    	IN PDRIVER_OBJECT DriverObject
    )
    {
    	UNICODE_STRING  uszDeviceString;
    	//
    	//  By default the I/O device is configured incorrectly or the 
    	// configuration parameters to the driver are incorrect.
    	//
    	NTSTATUS        ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
    
    	if (g_ActivateInfo.bActivated)
        //
        // restore the call back routine, thus givinig chance to the 
        // user mode application to unload dynamically the driver
        //
        ntStatus = PsRemoveLoadImageNotifyRoutine(ImageCallback);
    
    	IoDeleteDevice(DriverObject->DeviceObject);
    
    	RtlInitUnicodeString(&uszDeviceString, L"\\DosDevices\\ProcObsrv");
    	IoDeleteSymbolicLink(&uszDeviceString);
    }

ProcessListSingleHead.Next = NULL;

while (entry != listHead)
{

PPROCESS_LIST list = (PPROCESS_LIST)CONTAINING_RECORD(entry, PROCESS_LIST, LinkField);
DbgPrint(“Handle is %d”, ProcessId);
if (list->ProcessId == ProcessId) …;

entry = entry->Next;

}

Look how PushEntryList() works

https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/wdm/nf-wdm-pushentrylist

[begin quote]

PushEntryList sets ListHead->Next to Entry, and Entry->Next to point to the old first entry of the list.

[end quote]

Yo have initialised ProcessListSingleHead.Next to NULL. What do you think is going to happen when you reach the last entry in the list? Its "Next’ field is going to be NULL, rather than point to the list head, because of the way you have initialised it.

Therefore, you just dereference NULL pointer on the final iteration of the loop. Have you got anymore questions why you crash???

In order to make it work the way you expect it to you have to initialize it like “ProcessListSingleHead.Next = &ProcessListSingleHead;”

Anton Bassov

anton_bassov wrote:

In order to make it work the way you expect it to you have to initialize it like “ProcessListSingleHead.Next = &ProcessListSingleHead;”

Or, alternatively, use the function that was SPECIFICALLY designed for
this purpose: InitializeSListHead.

Or, alternatively, use the function that was SPECIFICALLY designed for this purpose: InitializeSListHead.

True, but my point was that, after having been initialised to NULL, the first list entry is obviously never going to point to the list head, i.e. to itself. To be honest, it really amazes me that someone had to go the NTDEV in order to find a bug like that - it seems to be laying right on the surface, don’t you think. I know we were all inexperienced once, but in this particular case the OP obviously did not even try to do his"homework"…

Anton Bassov