LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

DLL access violation - unless caller's FP is open.

Solved!
Go to solution

Greetings!

I've been using a DLL to control a device for many months without any problem.  The DLL is accessed by a reentrant VI (and only by that VI).  The reentrant caller (configured to "preallocate clones) is "wrapped" by a non-reentrant VI - which my code uses.

Now I've made a copy of the non-reentrant VI and have it open a renamed/copy of the DLL. So there are two DLLs loaded, each talking to a different device.

Shortly after "Initializing" the two DLLs I'm seeing a "Access Violation" error that closes/crashes LabVIEW (, though, leaves "LabVIEW.exe" running in Task Manager).  I put a breakpoint immediately after the "Initialize-DLLs" step.  The program crashes a couple of seconds after hitting the breakpoint.

It seems that this problem doesn't occur if - prior to running the code - I open the front panel of either non-reentrant "wrapper" VIs.

I know this description is a bit vague.  The program is massive and it would be very time-consuming to carve-out a shareable example.  Still, any ideas are appreciated.

Cheers!

0 Kudos
Message 1 of 15
(7,454 Views)

I assume this is an unmanaged Win32 dll? Even though the dlls are copied (and with different names both will be loaded in the process space) they may still access a shared resource internally (some sort of resource, impossible to say without any actual information) that could cause problems. If it is an unmanaged Win32 lib LabVIEW can do little to prevent crashes of this nature if the library encounters an error like this.

 

Perhaps it would be easier to "carve out" the VIs that wrap the dlls, those dll files and then create a new example main VI that performs the calls on the VIs? It would make things a lot easier for us to provide targeted assistance. It might also help reveal whether the issue is really related to this area specifically and not something else in your architecture.

0 Kudos
Message 2 of 15
(7,422 Views)

tyk has already explained it to you. Basically you can't just go and create renamed copies of DLLs to manage multiple resources unless the DLL is specifically written to do so. But it would usually be more straightforward for a DLL developer to actually write the DLL in such a way that it can access multiple devices at the same time by implementing a session based device handling where the user passes a refnum or handle of some sort from function to function and the DLL manages all the information including the device state to communicate with a particular device.

If the programmer found this to cumbersome he most likely didn't care either about making sure that two different instances of the DLL would not stomp on each others feet in some way.

And managed (.Net) or unmanaged doesn't really matter in this case, both could be written in such a way that they stomp on each other in some ways, for instance by accessing a secondary low level driver library that does not protect the global communication resource (bus, interface) in a proper way with locking.

That it doesn't crash when you have the front panel open is most likely a red herring. It still somewhere somehow corrupts memory but not memory that is crucial to LabVIEWs operation at that time. By opening the front panel LabVIEW needs to allocate more memory to manage all the front panel resources and such and that changes the actual memory layout of the whole process significantly enough that your misbehaving DLL stomps somewhere into memory where it doesn't immediately lead to a crash. It still will eventually crash somewhere, for instance when you try to close the front panel or maybe when you try to close LabVIEW itself and it tries to clean up everything and stumbles over corrupted memory pointers that your DLL caused.

Rolf Kalbermatter
My Blog
0 Kudos
Message 3 of 15
(7,411 Views)

Thank you tyk, rolfk.

tyk: I'll try to share the DLL source-code (which I inherited).

The (Win32) DLL interacts with a removable USB drive.  Actually it's not a drive, it's a camera/PCB with USB port, but the people who developed the device and firmware built the API around the removable-drive interface (instead of an HID or VCP interface).

Based on your comments (tyk/rolfk), I'll look for some step that might share a resource with another DLL/copy running within the same (LabVIEW) process-space.

By the way, the error code is 0xc0000005 and it can occur about 8sec after initializing the DLL (while sitting at the breakpoint).

Thanks again!

0 Kudos
Message 4 of 15
(7,398 Views)

Hi tyk,

Here's the relevant DLL code.  As mentioned, this DLL logic has worked very reliably.

Two copies appear too work (performing data-acquisition) in parallel and without conflict (for 30+minutes, so far) - when the non-reentrant FP is opened/hidden.

 

Without opened FP, at the point the error occurs, only the function "DLL_Init" has been called in both DLLs.  As is, the DLL_Inits are called in close succession, though I tried a 500ms delay between calls with no effect (error still happened).

 

Because of the strange delay (8sec) after calling the second DLL_Init and before the error, I wonder if the DLL is allocating memory which LabVIEW later references for some other reason?  (I know, an example would be helpful...) 

0 Kudos
Message 5 of 15
(7,384 Views)

I'm certainly no C++ expert, and it appears to me that there are header files it references ("myVendor.h") and thus source files missing making things more difficult to really diagnose (one of the many challenges of the C++ compilation architecture but I digress).

 

Rather than us trying to understand the architecture and fill in the missing gaps with assumptions - you mention that you were supplied this by an external party. That means they might have information as to whether this dll could be hosted in parallel with multiple connections to "boards" via that ID I see via the Init function.

0 Kudos
Message 6 of 15
(7,376 Views)

I hoped the header files wouldn't be necessary in order to identify "resource" related syntax with the potential to "stomp" on neighboring process memory.  "myVendor.h" does #define the initial DAQ buffer-size constant, but DAQ buffer is reallocated later, prior to DAQ, based on finite-DAQ size.

 

Yes - the "ID" parameter allows the DLL to identify, and communicate with, a specific "drive". I created two EXEs - one for each DLL/copy (each communicating with a different "ID") - they run in parallel without errors and without interfering with each other.  This ID mechanism can even work when the two copies of the DLL are loaded by LabVIEW IDE.  Today the two DLLs ran in parallel for about 4 hours without error.  The application terminated normally, but the access-error appeared on restart - even with non-reentrant FP opened/hidden (1st time).

 

Unfortunately, obtaining help/information from the "external party" is not convenient.

 

It seems it's time to start "carving out" a test case!Smiley Happy

 

0 Kudos
Message 7 of 15
(7,361 Views)

The code as is shown is pretty terrible in terms of contained localness of resources. It basically starts up a background thread that communicates with the device and then puts everything into global variables to be picked up by the functions that you call from the application with some events thrown in for synchronization between the two. Analyzing where the possible conflict could come from is a major headache that nobody will want to do for free. There is also a chance that the actual conflict is happening in how the USB interface is accessed though it seems to be able to handle two isolated processes accessing it at the same time.

Your results are typical for a memory corruption bug. It seems to work sometimes but simply restarting your LabVIEW system or your computer changes the actual memory layout enough to cause the corruption to happen in a different and more or less serious location. I hate to say it but if the hardware device is designed as the driver code you showed, it would be nothing more than crap.

Rolf Kalbermatter
My Blog
0 Kudos
Message 8 of 15
(7,352 Views)

rolfk, I was hoping you'd take a look; thanks for the reply/appraisel.

The "external" vendor seems clueless regarding software design.  They actually supplied several unique DLLs - one for each unique board ID.

That said...

A single copy of the current DLL functions "rock-solid" (at least it's hard "crap") and I need to make the two-copy system work.  I'm not 100%sure the DLL is doing anything wrong!  Perhaps an errant process, elsewhere in the app, is attempting to "stomp" on the DLL's memory...  

0 Kudos
Message 9 of 15
(7,342 Views)

Well, the DLL looks really like a mix mash of styles. There are the two low level functions getDescriptor() and SendCommand() which look mostly like a copy past job from one of the Microsoft DDK samples and then the whole shenanigan around it which looks like from someone used to write low level embedded software in a C like language without quite all the features that real C has. 

 

if I would be tasked to make this work I would throw away everything in that C code except the low level communication routines like SendCommand(), ConnectDrive() (and because ConnectDrive() uses it also getDesriptor()) and then write a proper session based wrapper around it so that a single DLL can handle multiple devices at the same time.

 

Such a DLL would take maybe 1 or 2 days to develop for me. The nice thing in this respect is that it could also be done all in LabVIEW with just the above mentioned 3 functions implemented with minor modifications in a DLL. Then write a LabVIEW class that maintains all the necessary data variables to drive these function in the class private data. It wouldn't be really less work but for someone not so inclined with C programming it would still be significantly easier.

 

Trying to debug this monster with multiple renamed DLLs in memory is something that easily takes a lot more time than that and still is hard to proof that it actually works reliable. Not crashing your app is absolutely no proof that everything is right!!

 

And I'm pretty sure the DLL is doing something wrong. With all those global variables accessed by your API calls and at the same time the background acquisition thread without much of a serialization through semaphores or something similar, this is bound to create race conditions at some point which can result in crashes very easily.

 

I would love to tackle this but I don't have any hardware to test it nor can I do this amount of work for just good karma alone. Smiley Happy

Rolf Kalbermatter
My Blog
0 Kudos
Message 10 of 15
(7,323 Views)