Driver Design: Error handling in "Free" functions in drivers

Hey, I have a general driver design question: What kind of error handling you do in the “free” functions of your drivers if the component could not free itself correctly?
Also, What about errors inside the error handler?
Most of the time if these errors happen, it means that there’s a programming bug somewhere, in your code or in the code of used libraries…

Let’s look at an example:

// Functions to create and destroy objects.
// These objects can be anything, kernel objects or memory..
// These are used only for the example
NTSTATUS CreateObject(__out POBJECT* Object);
	
NTSTATUS FreeObject(__out POBJECT* Object);
	
// This is the state of this component
POBJECT g_FirstObject;
POBJECT g_SecondObject;

// This is a function to initialize the component
NTSTATUS InitializeComponent(VOID)
{
    NTSTATUS Status;
	
	// By the way: Should I check if this component has already been initialized?
	
	g_FirstObject = NULL;
	g_SecondObject = NULL;
	
    Status = CreateObject(&g_FirstObject);
      
	if (!NT_SUCCESS(Status))
	{
		LOG_ERROR("Could not create object A");
		goto cleanup;
	}
	
	Status = CreateObject(&g_SecondObject);
	
	if (!NT_SUCCESS(Status))
	{
		LOG_ERROR("Could not create object B");
		goto cleanup;
	}
	
cleanup:
    if (!NT_SUCCESS(Status))
    {
        // If the component could not initialize itself, 
        // Call the free function to free left-overs
        // What about errors in this path? (error is ignored)
		FreeComponent();
    }
}

NTSTATUS FreeComponent(VOID)
{
	NTSTAUTS Status;
	
	if (g_FirstObject) { 
		// This can also cause errors..
		// What should I do with an errors in this function?
		Status = FreeObject(&g_FirstObject);
		
		if (!NT_SUCCESS(Status)) { 
			
			return Status; 
		} 
	}
	
	if (g_SecondObject) { 
		Status = FreeObject(&g_SecondObject);
	
		if (!NT_SUCCESS(Status)) { 
			// [!!] Now the component is an unstable state.
			// FirstObject is freed, and the second object could not be freed
			// What should I do? 
			return Status;
		}
		
	}
	
	return STATUS_SUCCESS;
}	

free cannot fail. If you want to be pedantic and check for error conditions (duplicate free, corrupt list, buffer over/under run, etc.) you bugcheck on failure as there is no sensible path forward.

I don’t mean ExFreePool, it could be anything that can fail (ZwFreeVirtualMemory, ObCloseHandle, …)
I wanted to bug check on failure, but I don’t think I should shutdown the entire machine just because of a bug in my code if the system can continue working…

If ObCloseHandle fails, the system is broken and will die shortly anyway. Mark is right. You either ignore it, or you bugcheck.

Ok thank you

Failure of these Free functions may mean that something is wrong in your code (e.g. you are attempting to close non-existent handle or free non-commited/reserved block of virtual memory). I think you may log such errors in order to find some rare bugs.