LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

DLL throws exception after running many times

Solved!
Go to solution

Hi all,

 

I'm working with a DLL to transfer data over USB. It works well for some number of data, but eventually throws an exception after about 1.6 GB of data sent. There may be a memory leak in the DLL. It seems that if I close and reopen my application, it resets my data limit. I tried looking into the code and header file for ways to clear the resources, but I I don't know much about C programming.

 

The error is the standard 1097 error saying that a DLL threw an exception, at which point I can quit the application or continue with possibly corrupted memory (which causes the program to hang).

 

Can you help me to find a way to get around this limit? Can I perform the data loading part of the application in a separate executable that the user never sees, so I can close it periodically? I am not too familiar with communication between executables, so what is the easiest way to get started if that sounds like a good idea?

 

Thank you,

Gregory

0 Kudos
Message 1 of 15
(3,967 Views)

I am not sure, but dynamic load/unload of the DLL could fix your problem? Can you test it?

http://digital.ni.com/public.nsf/allkb/77594203D78D12278625729100758BE5

0 Kudos
Message 2 of 15
(3,930 Views)

Thank you, great idea! But, my attempt at it did not give any different results. I run this code once with "Unload DLL?" set to false to send the data, then again with "Unload DLL?" set to true. Still after about 200 runs with my data, I get the same error from the DLL.

 

temp.PNG

 

temp2.PNG

0 Kudos
Message 3 of 15
(3,906 Views)

I am out of ideas. Maybe there are published methods for this dll, like reset device? Something like that could help...?

0 Kudos
Message 4 of 15
(3,902 Views)

Seeing how many of those inputs are I32, your 1.6GB sounds like you might be encroaching in on the 2GB limit of an I32 with all of the handshaking characters.  Can you break your transfers down into smaller blocks <1GB then reset (close/re-open) the DLL while continuing to run from previous spot?

Help the Community (and future reviewers) by marking posts as follows:
If it helped - KUDOS
If it answers the issue - SOLUTION
0 Kudos
Message 5 of 15
(3,894 Views)

@Gregory wrote:

Thank you, great idea! But, my attempt at it did not give any different results. I run this code once with "Unload DLL?" set to false to send the data, then again with "Unload DLL?" set to true. Still after about 200 runs with my data, I get the same error from the DLL.

 

temp.PNG

 

temp2.PNG


This is most likely not really something you should be trying to solve from LabVIEW. If the DLL bombs somehow, all you can do from within LabVIEW is finding out that it does, nothing more. The correct course of action is to debug the DLL itself and find out why it crashes. 

 

That all said I wonder about the -1 in the length from the PLUT Data. That doesn't quite make much sense, unless the function treats this (incorrectly) as number of character bytes to store into the buffer and then appends an extra NULL byte to terminate the string. A horrible way of dealing with a string buffer in C. If it is a string that you pass into the function, then the length passed in is even more wrong as LabVIEW strings don't have a terminating NULL byte at all and the according array length node will consequently return one byte less than there was actually passed into the VI in the string. And things get definitely very awry if you pass in an empty string: The resulting length passed into the DLL function will be then -1 and if the DLL treats this in reality as an unsigned integer it will see a whooping 0xFFFFFFFF or 4 billion bytes of buffer length.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 6 of 15
(3,892 Views)

@Minions wrote:

Seeing how many of those inputs are I32, your 1.6GB sounds like you might be encroaching in on the 2GB limit of an I32 with all of the handshaking characters.  Can you break your transfers down into smaller blocks <1GB then reset (close/re-open) the DLL while continuing to run from previous spot?


Most likely you are onto something here too. VID and PID look like USB identifiers and they are in reality 16 bit unsigned integers. The DLL function may still declare them as int32_t and correctly cast them to the needed 16 bit unsigned integers internally, but it may just as much be that the person who set this Call Library Node up had little understanding about datatypes and how they relate to each other.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 7 of 15
(3,891 Views)

Hi Minions,

 

Yes, I do not send all the data at once, only around 16 MB at most. However, after 100-500 runs of this SubVI, I get the error from the DLL, even if I unload it by sending an empty path after every run.

0 Kudos
Message 8 of 15
(3,873 Views)

Hi Rolf, thank you for the comments. I did pull this code out of another application, so I don't know much about how it works. I was able to dig up some files from the DLL, including a header file and a Main.cpp (I assume that is C++ code?). I don't know if that helps diagnose the problem at all.

 

I'm currently trying to wrap the DLL functionality in a separate executable that I communicate to with network streams to see if that helps...

 

I can also try and not subtract 1 from the data size to see what happens!

0 Kudos
Message 9 of 15
(3,871 Views)
Solution
Accepted by topic author Gregory

Hooly **bleep**, that code has a terrible memory leak!!!!!!

 

LONG __stdcall WriteUSBDevice(LONG *VID, LONG *PID, UCHAR *data,LONG size, LONG GLV,LONG staddr)
{
	//create instance of CCyUSBDevice
	CCyUSBDevice *USBDevice;
	USBDevice = new CCyUSBDevice(NULL, CYUSBDRV_GUID, 1);
	//OpenDevice
	LONG num = 0;
	int vID;
	int pID;
	int d = 0;
	int 	devices = USBDevice->DeviceCount();
	do{
		USBDevice->Open(d);
		vID = USBDevice->VendorID;
		pID = USBDevice->ProductID;
		d++;
	} while ((d<devices) && (vID != (*VID)) && (pID != (*PID)));
	if ((vID == (*VID)) && (pID == (*PID))){
		num = 0;
	}
	else if (d >= devices){
		num = 1;
	}
	else{
		num = 3;
	}
	*VID = vID;
	*PID = pID;
	if (num != 0){ return num; }

	int i;
	UCHAR *array = new unsigned char[size];
	array = data;
//	for (i = 0; i < size; i++)
//	{
//		*(array++) = i;
//	}
//	size *= 4;
	bool err;
	err = false;
	if (USBDevice->BulkOutEndPt){
		err = USBDevice->BulkOutEndPt->XferData((unsigned char*) array, size);
	}
	data = array;
	if (err = true)num =0;//OK
	else num = 200;//NG

delete[] array;
delete USBDevice;
return num;
}

It first creates an array of the size indicated by the size parameter, the one you pass in with 1 decrement from the buffer passed into the LabVIEW VI. Then it immediately overwrites that allocated pointer with the pointer received from the caller. Then after the BulkOut call it assigns the array pointer back to the data pointer passed in, which is complete nonsense, and last but not least it tries to delete the array which is not the original array allocated in the beginning but the data pointer passed in from LabVIEW and which the delete operator has no business about messing with, nor is it likely able to as it is probably using a different allocator althogether than what LabVIEW is using.

 

Aside from that, creating a new device object for every single request and opening the communication channel to it to then deallocate it again is also terribly inefficient.

Wrapping this into a seperate executable to then call through network streams is simply building more crap on a wrecked piece of software.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 10 of 15
(3,860 Views)