Backtracing the usermode stack of a thread during a minifilter callback function - driver

I'm trying to backtrace the usermode stack of a thread during a minifilter callback function.
Assuming that I'm in the same context as the calling thread, getting the thread stack address from it's TEB/TIB and processing the addresses on that stack should allow me to backtrace it's stack.
Since the addresses I'm getting are not the expected usermode modules that are calling the system-call,
there must be something wrong I'm doing.
I will be glad if you would point me to the correct direction.
Thanks in advance.
Following is the code that is reading the stack content:
pTEB = (PVOID *)((char *)pThread + 0x20);
// Read TIB
pTib = (NT_TIB*)pTEB;
stackBottom = (PVOID*)pTib->StackLimit;
stackTop = (PVOID*)pTib->StackBase;
LogDbgView(("stackBottom=%p, stackTop=%p",stackBottom, stackTop));
if (!MyReadMemory(IoGetCurrentProcess(), stackBottom, buf, stackTop-stackBottom))
{
LogDbgView(("Read Memory = %x",buf));
LogDbgView(("Read Memory = %x",buf+8));
LogDbgView(("Read Memory = %x",buf+16));
LogDbgView(("Read Memory = %x",buf+24));
}
Below are the functions that gets the module names and addresses:
PVOID LoadModulesInformation()
{
PVOID pSystemInfoBuffer = NULL;
__try
{
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
ULONG SystemInfoBufferSize = 0;
status = ZwQuerySystemInformation(SystemModuleInformation,
&SystemInfoBufferSize,
0,
&SystemInfoBufferSize);
if (!SystemInfoBufferSize)
return NULL;
pSystemInfoBuffer = (PVOID)ExAllocatePool(NonPagedPool, SystemInfoBufferSize*2);
if (!pSystemInfoBuffer)
return NULL;
memset(pSystemInfoBuffer, 0, SystemInfoBufferSize*2);
status = ZwQuerySystemInformation(SystemModuleInformation,
pSystemInfoBuffer,
SystemInfoBufferSize*2,
&SystemInfoBufferSize);
if (NT_SUCCESS(status))
{
return pSystemInfoBuffer;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
return NULL;
}
PUNICODE_STRING findModuleName(PVOID addr, PVOID pSystemInfoBuffer, ULONG Tag FILE_AND_LINE_ARGS)
{
PVOID pModuleBase = NULL;
PCHAR pCharRet=NULL;
PUNICODE_STRING pus = NULL;
__try
{
if (pSystemInfoBuffer != NULL && MmIsAddressValid(addr))
{
PSYSTEM_MODULE_ENTRY pSysModuleEntry = ((PSYSTEM_MODULE_INFORMATION)(pSystemInfoBuffer))->Module;
ULONG i;
for (i = 0; i <((PSYSTEM_MODULE_INFORMATION)(pSystemInfoBuffer))->Count; i++)
{
if ((pSysModuleEntry[i].Base <= addr) && (pSysModuleEntry[i].Size < ((ULONG)addr - (ULONG)pSysModuleEntry[i].Base)))
{
pCharRet = pSysModuleEntry[i].ImageName+pSysModuleEntry[i].PathLength;
break;
}
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
pCharRet = NULL;
}
if (pCharRet)
{
pus = UtlpCharToUnicode(pCharRet, TRUE, TRUE, Tag FILE_AND_LINE_PARAMS);
}
else
{
pus = UtlpCharToUnicode("UNKNOWN", TRUE, TRUE, Tag FILE_AND_LINE_PARAMS);
}
return pus;
}

pTEB = (PVOID *)((char *)pThread + 0x20);
Don't do this at all, even in PoC. Structure layout changes time to time. You can use PsGetProcessPeb instead (see here how https://code.google.com/p/arkitlib/source/browse/trunk/ARKitDrv/Ps.c)
LogDbgView(("Read Memory = %x",buf));
You don`t read memory at buf address, you read value of buf instead. In C you must dereference pointer to read memory from there. Like this
LogDbgView(("Read Memory = %x",(PVOID)*buf));
LogDbgView(("Read Memory = %x",buf+8));
To be able to compile for x86 as well as for x64 you must avoid such things. Instead, use sizeof(PVOID):
LogDbgView(("Read Memory = %x",(PVOID)*(buf+sizeof(PVOID))));

Related

Cloning an independent IRP

I am new to driver development and I want to be able to send an IRP request to the ((PDEVICE_EXTENSION)myDevice->DeviceExtension)->lowerDevice. This IRP request should be treated by the lowerDevice the same way as if I were to simply forward the incoming IRP. I am able to successfully build and send the IRP but it errors at the lowerDevice, Access violation - code c0000005. I greatly appreciate any help!
NTSTATUS DispatchRead(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
KEVENT event;
PIRP lowerIrp;
IO_STATUS_BLOCK ioStatus;
NTSTATUS status;
PIO_STACK_LOCATION pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);
KeInitializeEvent(&event, NotificationEvent, FALSE);
SIZE_T len = max(pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength, pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength);
PVOID InputBuffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, len, 'ITag');
if (!InputBuffer) {
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(InputBuffer, Irp->AssociatedIrp.SystemBuffer, pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength);
Irp->IoStatus.Information = pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength;
LARGE_INTEGER startingOffset;
startingOffset.QuadPart = (LONGLONG)0;
lowerIrp = IoBuildSynchronousFsdRequest(
IRP_MJ_READ,
((PDEVICE_EXTENSION)myDevice->DeviceExtension)->lowerDevice,
InputBuffer,
(ULONG)len,
&startingOffset,
&event,
&ioStatus
);
if (NULL == lowerIrp) {
ExFreePool(InputBuffer);
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
IoSetCompletionRoutine(lowerIrp, completionRoutine, NULL, TRUE, TRUE, TRUE);
status = IoCallDriver(((PDEVICE_EXTENSION)myDevice->DeviceExtension)->lowerDevice, lowerIrp);
if (status == STATUS_PENDING) {
status = KeWaitForSingleObject(
&event,
Executive,
KernelMode,
FALSE, // Not alertable
NULL);
status = ioStatus.Status;
}
return status;
}

wxWidgets serial Commuication

I have absolutely no experience in programming serial communication and since I'm stuck with my code I'd really appreciate your help! Thank you already!
So now to my problem:
I got a generator on which are several different sensors who communicate over CAN with a microcontroller. This mc itself communicates with a device from USBTin again over CAN. On the USBTin, a little board, is mainly a CAN controller and a microcontroller which are precoded from its developer.
So my task now is to open my COM Port, send the right messages to the USBTin (those are "S5" for the baudrate and 'O' for Open CAN) and then receive the data.
First of all the functions and my problem:
The problem is that in my output textfield stands something like "PPPPPPPPPP,Râö". There are always these 10 P's and some random characters. I have no idea where the P's or these additional "Râö" comes from. The actual output string shoud be something like "T1E18001F8". I tested that with hTerm, which is a terminal programm for serial communication.
OPEN:
long Serial::Open()
{
if (IsOpened()) return 0;
#ifdef UNICODE
wstring wtext(port.begin(),port.end());
#else
string wtext = port;
#endif
hComm = CreateFile(wtext.c_str(),
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
0);
if (hComm == INVALID_HANDLE_VALUE) {return 1;}
if (PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR |
PURGE_RXCLEAR) == 0) {return 2;}//purge
//get initial state
DCB dcbOri;
bool fSuccess;
fSuccess = GetCommState(hComm, &dcbOri);
if (!fSuccess) {return 3;}
DCB dcb1 = dcbOri;
dcb1.BaudRate = baud;
if (parity == 'E') dcb1.Parity = EVENPARITY;
else if (parity == 'O') dcb1.Parity = ODDPARITY;
else if (parity == 'M') dcb1.Parity = MARKPARITY;
else if (parity == 'S') dcb1.Parity = SPACEPARITY;
else if (parity == 'N') dcb1.Parity = NOPARITY;
dcb1.ByteSize = (BYTE)dsize;
if(stopbits==2) dcb1.StopBits = TWOSTOPBITS;
else if (stopbits == 1.5) dcb1.StopBits = ONE5STOPBITS;
else if (stopbits == 1) dcb1.StopBits = ONE5STOPBITS;
dcb1.fOutxCtsFlow = false;
dcb1.fOutxDsrFlow = false;
dcb1.fOutX = false;
dcb1.fDtrControl = DTR_CONTROL_DISABLE;
dcb1.fRtsControl = RTS_CONTROL_DISABLE;
fSuccess = SetCommState(hComm, &dcb1);
delay(60);
if (!fSuccess) {return 4;}
fSuccess = GetCommState(hComm, &dcb1);
if (!fSuccess) {return 5;}
osReader = { 0 };// Create the overlapped event. Must be closed before
exiting to avoid a handle leak.
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osReader.hEvent == NULL) {return 6;}// Error creating overlapped event;
abort.
fWaitingOnRead = FALSE;
osWrite = { 0 };
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osWrite.hEvent == NULL) {return 7;}
if (!GetCommTimeouts(hComm, &timeouts_ori)) { return 8; } // Error getting
time-outs.
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 20;
timeouts.ReadTotalTimeoutMultiplier = 15;
timeouts.ReadTotalTimeoutConstant = 100;
timeouts.WriteTotalTimeoutMultiplier = 15;
timeouts.WriteTotalTimeoutConstant = 100;
if (!SetCommTimeouts(hComm, &timeouts)) { return 9;} // Error setting time-
outs.
return 0;
}
WRITE:
bool Serial::Write(char *data)
{
if (!IsOpened()) {
return false;
}
BOOL fRes;
DWORD dwWritten;
long n = strlen(data);
if (n < 0) n = 0;
else if(n > 1024) n = 1024;
// Issue write.
if (!WriteFile(hComm, data, n, &dwWritten, &osWrite)) {
if (GetLastError() != ERROR_IO_PENDING) {fRes = FALSE;}// WriteFile
failed, but it isn't delayed. Report error and abort.
else {// Write is pending.
if (!GetOverlappedResult(hComm, &osWrite, &dwWritten, TRUE))
fRes = FALSE;
else fRes = TRUE;// Write operation completed successfully.
}
}
else fRes = TRUE;// WriteFile completed immediately.
return fRes;
}
READCHAR:
char Serial::ReadChar(bool& success)
{
success = false;
if (!IsOpened()) {return 0;}
DWORD dwRead;
DWORD length=1;
BYTE* data = (BYTE*)(&rxchar);
//the creation of the overlapped read operation
if (!fWaitingOnRead) {
// Issue read operation.
if (!ReadFile(hComm, data, length, &dwRead, &osReader)) {
if (GetLastError() != ERROR_IO_PENDING) { /*Error*/}
else { fWaitingOnRead = TRUE; /*Waiting*/}
}
else {if(dwRead==length) success = true;}//success
}
//detection of the completion of an overlapped read operation
DWORD dwRes;
if (fWaitingOnRead) {
dwRes = WaitForSingleObject(osReader.hEvent, READ_TIMEOUT);
switch (dwRes)
{
// Read completed.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(hComm, &osReader, &dwRead, FALSE))
{/*Error*/ }
else {
if (dwRead == length) success = true;
fWaitingOnRead = FALSE;// Reset flag so that another
opertion
can be issued.
}// Read completed successfully.
break;
case WAIT_TIMEOUT:
// Operation isn't complete yet.
break;
default:
// Error in the WaitForSingleObject;
break;
}
}
return rxchar;
}
And Finally the excerpt of the main in wxWidgets to display the received data:
void GUI_1_2Frame::OnConnectButtonClick(wxCommandEvent& (event))
{
char tempString[10] = {0};
bool ReadChar_success = true;
char temp_Char;
/* Preset Serial Port setting */
Serial com(com_x, 115200, 8, NOPARITY, 1);
char* buffer;
if(connection_flag)
{
/* Port was connected, Disconnect Button unsed*/
com.Close();
wxMessageBox(_("Port closed"),_("Info!"),wxICON_INFORMATION);
connection_flag = 0;
ConnectButton->SetLabel("Connect");
TextCtrl1->SetValue("");
}
else
{
/* If open() == true -> INVALID HANDLE */
if(com.Open())
{
wxMessageBox(_("Port not available"),_("ERROR!"),wxICON_ERROR);
}
else /* Port Opened */
{
TextCtrl1->SetValue(com.GetPort());
ConnectButton->SetLabel("Disconnect");
connection_flag = 1;
}
if(com.Write("S5"))
{
TextCtrl1->SetValue("Baudrate sent!\n");
delay(100);
if(com.WriteChar('O'))
{
TextCtrl1->SetValue("Baudrate & Open Command sent!");
int i =0;
while(i<10)
{
temp_Char = com.ReadChar(ReadChar_success);
tempString[i] = temp_Char;
i++;
}
com.WriteChar('C');
com.Close();
//com.readSerialPort(data, MAX_DATA_LENGTH);
TextCtrl2->SetValue(tempString);
//wxMessageOutput::Get()->Printf("%s", tempString);
}
else
{
TextCtrl1->SetValue("Open Command Error!"); }
}
else
{
TextCtrl1->SetValue("Error!");
}
}
}
Since I am not native speaking englisch I say sorry for my language mistakes.
Thank everybody a lot and again I really appreciate every single hint!
Greetings,
MSol

Reading file in pre-cleanup stage in a deferred work item

I writing a Windows Minifilter Driver which needs to read the entire file (only files with size up to a specific threshold) on IRP_MJ_CLEANUP. As FltReadFile may not be called from the preop callback I queued the job to a work queue and did it there. When I finish reading the file I call FltCompletePendedPreOperation and invoke the post-cleanup callback which also handles the post operation as deferred work. Here are snippets of my code:
static NTSTATUS HandlePreCleanup(_In_ PFLT_CALLBACK_DATA Data,
_Out_ PVOID *Context)
{
NTSTATUS Status = STATUS_SUCCESS;
PFLT_INSTANCE Instance;
PFILE_OBJECT FileObject;
PVOID Buffer = NULL;
LARGE_INTEGER FileOffset;
FileObject = Data->Iopb->TargetFileObject;
Instance = Data->Iopb->TargetInstance;
Buffer = ExAllocatePoolWithTag(PagedPool,
(ULONG) FILE_CHUNK_SIZE,
PPFILTER_FILE_POOLTAG);
if (Buffer == NULL) {
PPERROR("Failed allocating file chunk\n");
Status = STATUS_MEMORY_NOT_ALLOCATED;
goto out;
}
FileOffset.QuadPart = 0;
for (;;) {
ULONG BytesRead;
Status = FltReadFile(
Instance, FileObject, &FileOffset,
(ULONG) FILE_CHUNK_SIZE, Buffer,
FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET,
&BytesRead, NULL, NULL
);
if (!NT_SUCCESS(Status)) {
if (Status == STATUS_END_OF_FILE) {
Status = STATUS_SUCCESS;
break;
}
PPERROR("Failed reading from file %wZ: error %d\n",
&FileObject->FileName, Status);
goto out;
}
FileOffset.QuadPart += BytesRead;
}
out:
if (Buffer != NULL) {
ExFreePoolWithTag(Buffer, PPFILTER_FILE_POOLTAG);
}
return Status;
}
static VOID DeferredPreCallback(_In_ PFLT_DEFERRED_IO_WORKITEM WorkItem,
_In_ PFLT_CALLBACK_DATA Data,
_In_opt_ PVOID Context)
{
NTSTATUS Status = STATUS_SUCCESS;
PVOID PostContext = NULL;
UNREFERENCED_PARAMETER(Context);
switch (Data->Iopb->MajorFunction) {
case IRP_MJ_CLEANUP:
Status = HandlePreCleanup(Data, &PostContext);
break;
default:
NT_ASSERTMSG("Unexpected deferred pre callback operation",
FALSE);
break;
}
FltCompletePendedPreOperation(Data,
FLT_PREOP_SUCCESS_WITH_CALLBACK,
PostContext);
FltFreeDeferredIoWorkItem(WorkItem);
}
static NTSTATUS QueueWork(_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PFLT_DEFERRED_IO_WORKITEM_ROUTINE WorkRoutine,
_In_ PVOID Context)
{
NTSTATUS Status = STATUS_SUCCESS;
PFLT_DEFERRED_IO_WORKITEM WorkItem = NULL;
WorkItem = FltAllocateDeferredIoWorkItem();
if (WorkItem == NULL) {
Status = STATUS_MEMORY_NOT_ALLOCATED;
PPERROR("Failed allocating work item\n");
goto failed;
}
Status = FltQueueDeferredIoWorkItem(WorkItem, Data, WorkRoutine,
CriticalWorkQueue, Context);
if (!NT_SUCCESS(Status)) {
PPERROR("Failed queuing work item to queue: error %d\n",
Status);
goto failed;
}
return STATUS_SUCCESS;
failed:
if (WorkItem != NULL) {
FltFreeDeferredIoWorkItem(WorkItem);
}
return Status;
}
static FLT_PREOP_CALLBACK_STATUS DeferPreCallback(
_Inout_ PFLT_CALLBACK_DATA Data,
_In_ PCFLT_RELATED_OBJECTS FltObjects,
_Out_ PVOID *CompletionContext
)
{
NTSTATUS Status = STATUS_SUCCESS;
UNREFERENCED_PARAMETER(FltObjects);
UNREFERENCED_PARAMETER(CompletionContext);
Status = QueueWork(Data, DeferredPreCallback, NULL);
if (!NT_SUCCESS(Status)) {
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}
return FLT_PREOP_PENDING;
}
CONST FLT_OPERATION_REGISTRATION OperationRegistrations[] = {
{
IRP_MJ_CLEANUP,
0,
DeferPreCallback,
DeferPostCallback,
NULL
},
{ IRP_MJ_OPERATION_END },
};
This proves to work for a while but the system seems to hang (deadlock?) after a while. The problem seems to be with the call to FltReadFile since the hang does not occur when removing this call. Any ideas on why this might happen or how to debug it further?
Well, apparently the problem was that FltReadFile was given a FileOffset which was not aligned with the volume sector size. This is a problem apparently if FileObject was created for non-cached IO (See the Remarks section in https://msdn.microsoft.com/en-us/library/windows/hardware/ff544286(v=vs.85).aspx). As I have no control on how the FileObject in question was created there may be cases in which it was indeed created for non-cached IO. To fix this I added the following check at the end of the for(;;) loop:
if (BytesRead < FILE_CHUNK_SIZE) {
break;
}
This should work if FILE_CHUNK_SIZE is a multiple of the volume sector size.

How get trap with indy TidSNMP component

I'm using c++builderXE with Indy 10.5.7 and I'm trying to receive trap from another agent snmp.
I have no info describing how to do the program to receive trap.
Below you can find the snippet of code which I'm trying to use now.
The ReceiveTrap() method always return 0, which means non data received.
I tested the PC configuration with another program I made several years ago using spare API and the trap is received so I don't this it should be a configuration problem.
Have you some suggestions of hat I'm wrong in the routine below?
void __fastcall TForm1::LabelReceiveTrapClick(TObject * Sender)
{
static bool status = false;
int ists;
String Fun = "[SimpleReceiveTrap] ";
TSNMPInfo * infoSnmp = 0;
try
{
status = !status;
if (status)
{
std::auto_ptr< TIdSNMP >clientSnmp(new TIdSNMP(NULL));
clientSnmp->Community = "public";
clientSnmp->ReceiveTimeout = 1000;
clientSnmp->Binding->Port = 162;
while (status)
{
Application->ProcessMessages();
ists = clientSnmp->ReceiveTrap();
Mylog(L"%s ReceiveTrap status = [%d]", Fun.c_str(), ists);
if (ists > 0)
{
infoSnmp = clientSnmp->Trap;
}
}
}
}
catch (Exception & ex)
{
Mylog(L"%s ERROR", Fun.c_str(), ex.Message.c_str());
}
}
That is not the correct way to set the listening Port for receiving traps. Reading the Binding property allocates and binds a socket to a local IP/Port using the TIdSNMP::BoundIP and TIdSNMP::BoundPort properties. You can't change that socket's local Port after it has already been bound, so your assignment of the Binding->Port property is effectively a no-op.
For that matter, you are trying to manipulate the wrong socket anyway. The Binding socket is used for sending queries to the remote SNMP system. TIdSNMP uses a separate socket for receiving traps. TIdSNMP has a separate TrapPort property for specifying the listening Port of that socket. When the Binding is accessed, the trap socket is allocated and bound to Binding->IP and TIdSNMP::TrapPort. The TrapPort property defaults to 162.
std::auto_ptr< TIdSNMP >clientSnmp(new TIdSNMP(NULL));
clientSnmp->Community = "public";
clientSnmp->ReceiveTimeout = 1000;
clientSnmp->TrapPort = 162; // <--
...
ists = clientSnmp->ReceiveTrap();
Looking at Indy's changelog, there have been some trap-related changes to the listening socket since 10.5.7 was released, so you may need to upgrade to a newer Indy version to get bug fixes. Or you could download the latest version and then just add IdSNMP.pas to your project directly, at least.
Using only the Indi component I can't read the trap rev 2c
But I found a solution using TWSocket and TSNMPInfo which seems to works well
Belowe the code I used:
To get the data I use a TWSocket fro FPiette components suite:
void __fastcall TForm1::LabelStartServerTracSnmpClick(TObject * Sender)
{
String Fun = "[LabelStartServerTracSnmp] ";
try
{
if (WSocket1->State == wsClosed)
{
WSocket1->Proto = "udp";
WSocket1->Addr = "0.0.0.0";
WSocket1->Port = 162;
WSocket1->Listen();
}
else
{
WSocket1->Close();
}
}
catch (Exception & ex)
{
Mylog(L"%s ERROR: [%s]", Fun.c_str(), ex.Message.c_str());
}
}
To analyze the data received I use the Indy
void __fastcall TForm1::WSocket1DataAvailable(TObject * Sender, WORD ErrCode)
{
char buffer[1024];
int len, cnt, srcLen;
TSockAddrIn srcSocket;
String rcvmsg, remHost, s1, s2, Fun = "[WSocket1DataAvailable] ";
TIdSNMP * clientSnmp = NULL;
TSNMPInfo * infoSnmp = NULL;
try
{
srcLen = sizeof(srcSocket);
len = WSocket1->ReceiveFrom(buffer, sizeof(buffer), srcSocket, srcLen);
if (len >= 0)
{
buffer[len] = 0;
rcvmsg = String(buffer, len);
__try
{
clientSnmp = new TIdSNMP(NULL);
infoSnmp = new TSNMPInfo(clientSnmp);
infoSnmp->DecodeBuf(rcvmsg);
cnt = infoSnmp->ValueCount;
if (cnt > 0)
{
// ---------------------------------------------------
for (int idx = 0; idx < cnt; ++idx)
{
s1 = infoSnmp->ValueOID[idx];
s2 = infoSnmp->Value[idx];
Mylog(L"[%s] Trap : [%s] => [%s]", s1.c_str(), s2.c_str());
}
}
}
__finally
{
if (infoSnmp)
{
delete infoSnmp;
infoSnmp = 0;
}
if (clientSnmp)
{
delete clientSnmp;
clientSnmp = 0;
}
}
}
}
catch (Exception & ex)
{
Mylog(L"%s ERROR", Fun.c_str(), ex.Message.c_str());
}
}

zError function call in zLib impacting performance

When using zlib 1.25 in an iOS project, I've noticed in my profiler (Instruments) that the function zError is being called repeatedly, and is occupying 50% of the overall inflate time.
Does anyone know why zError would be getting invoked like this? I don't call it anywhere in my own code, which is a pretty boilerplate inflate function, pasted below:
int UPNExtractorGZInflate(const void *src, int srcLen, void *dst, int dstLen) {
z_stream strm = {0};
strm.total_in = strm.avail_in = srcLen;
strm.total_out = strm.avail_out = dstLen;
strm.next_in = (Bytef *) src;
strm.next_out = (Bytef *) dst;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
int err = -1;
int ret = -1;
err = inflateInit2(&strm, (15 + 16)); //15 window bits, and the +16 tells zlib to decode gzip
if (err == Z_OK) {
err = inflate(&strm, Z_FINISH);
if (err == Z_STREAM_END) {
ret = strm.total_out;
}
else {
inflateEnd(&strm);
return err;
}
}
else {
inflateEnd(&strm);
return err;
}
inflateEnd(&strm);
return ret;
}
And here is the relevant profiler output (notice zError taking 50% of the overall inflate time):
zError isn't called by any zlib function. If you're not calling it, then your profiler is misidentifying the function taking that time.

Resources