Virtual serial driver reads and writes at the same time causing a crash.

I am studying a PCI virtual serial port driver. When reading and writing alone, everything is normal, but when reading and writing Windows at the same time, the blue screen will crash instantly.
NTSTATUS
WriteIoTargetMemory(PDEVICE_CONTEXT pContext, PVOID buffer, ULONG bytes, ULONG offset, PULONG nBytes)
{
ULONG retByt = 0;
NTSTATUS status;
ULONGLONG timeOutMs = 2;
WDF_MEMORY_DESCRIPTOR inputDescriptor;
WDF_REQUEST_SEND_OPTIONS requestOptions;
WRITEBAR_MAILBOX_PARAMS writeMailBox;

if (pContext->IoTarget == NULL){
	DbgPrint("Error: WriteIoTargetMemory IoTarget is NULL.\n");
	return STATUS_INVALID_PARAMETER;
}
writeMailBox.busunit = bytes;
writeMailBox.offset = offset;
writeMailBox.value = *(PULONG)buffer;

//DbgPrint("WriteIoTargetData:%#x\n", writeMailBox.value);
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&inputDescriptor, (PVOID)&writeMailBox, sizeof(writeMailBox));
WDF_REQUEST_SEND_OPTIONS_INIT(&requestOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT | WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);

if (pContext->regVarContext.recvInerval > 1){
	timeOutMs = pContext->regVarContext.recvInerval / 2;
}else{
	timeOutMs = 1;
}
requestOptions.Timeout = WDF_REL_TIMEOUT_IN_MS(timeOutMs);
status = WdfIoTargetSendIoctlSynchronously(pContext->IoTarget, NULL, pContext->regVarContext.writeMemoryCtlcode, &inputDescriptor, NULL, &requestOptions, &retByt);

if (!NT_SUCCESS(status)) {
	DbgPrint("Error: WriteIoTargetMemory:%#x\n", status);
	return status;
}
*nBytes = status;

return status;

}

NTSTATUS
ReadIoTargetMemory(PDEVICE_CONTEXT pContext, PVOID buffer, ULONG bytes, ULONG offset, PULONG nBytes)
{
ULONG retByt = 0;
NTSTATUS status = STATUS_SUCCESS;
ULONGLONG timeOutMs = 2;
WDF_MEMORY_DESCRIPTOR inputDescriptor, outputDescriptor;
WDF_REQUEST_SEND_OPTIONS requestOptions;
READBAR_MAILBOX_PARAMS readMailBox;
PWDF_MEMORY_DESCRIPTOR pInputDescriptor = NULL, pOutputDescriptor = NULL;

if ((pContext->IoTarget == NULL) || (nBytes == NULL) || (buffer == NULL)){
	return STATUS_INVALID_PARAMETER;
}
readMailBox.busunit = bytes;
readMailBox.offset = offset;

WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&inputDescriptor, (PVOID)&readMailBox, sizeof(readMailBox));
pInputDescriptor = &inputDescriptor;
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDescriptor, buffer, bytes);
pOutputDescriptor = &outputDescriptor;
WDF_REQUEST_SEND_OPTIONS_INIT(&requestOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT | WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);

if (pContext->regVarContext.recvInerval > 1){
	timeOutMs = pContext->regVarContext.recvInerval / 2;
}else{
	timeOutMs = 1;
}
requestOptions.Timeout = WDF_REL_TIMEOUT_IN_MS(timeOutMs);
status = WdfIoTargetSendIoctlSynchronously(pContext->IoTarget, NULL, pContext->regVarContext.readMemoryCtlcode, pInputDescriptor, pOutputDescriptor, &requestOptions, &retByt);
if (!NT_SUCCESS(status)) {
	DbgPrint("Error: ReadIoTargetMemory:%#x\n", status);
	return status;
}
*nBytes = retByt;

return status;

}

Windbg blue screen log error pointing here–
status = WdfIoTargetSendIoctlSynchronously(pContext->IoTarget, NULL, pContext->regVarContext.readMemoryCtlcode, pInputDescriptor, pOutputDescriptor, &requestOptions, &retByt);

!analyze -v, please.

Peter

WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&inputDescriptor, (PVOID)&readMailBox, sizeof(readMailBox));
pInputDescriptor = &inputDescriptor;
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputDescriptor, buffer, bytes);
pOutputDescriptor = &outputDescriptor;

I’m always amazed when I see code like this, and it happens surprisingly often. Are There really C programmers who do not understand how to pass parameters?