LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

DLL malloc() and free() and common heap space

Solved!
Go to solution

Hello,

 

In continuation with my last post, I've got another problem, that might be the same, or it might be different.

 

I have 2 DLLs, a driver (driver.dll) and a support package (support.dll).

 

If support.dll has the function MyDLLAllocFunction() and it is simply:

void *MyDLLAllocFunction(void) {

  return malloc(100);

 

And then in driver.dll I do

 

void *x;

x = MyDLLAllocFunction();

free(x);

 

I get an error at "free(x)" saying that it wasn't malloc'd or calloc'd, but it was, however in another DLL. How would I get all the library modules to share the same heap?

 

I'm using WinXP and CVI 9.0.

 

I observe this issue with DLLs (support.dll) that wasn't compiled with CVI, but where the driver.dll was, e.g. when I'm trying to use the library PCRE.dll compiled with MINGW32 (under Cygwin) and I need to do a free().

 

Thanks,

Jason. 

0 Kudos
Message 1 of 9
(10,916 Views)
I should say, I see this problem with NI implementations and as well as having my NI dll call a 3rd party DLL that requires a free() (without providing its own function) to release memory to the heap.
0 Kudos
Message 2 of 9
(10,912 Views)

Hello Jason,

 

The problem that you're having is that you are trying to mix and match the CVI ANSI C library with the ANSI C library of another compiler, and these cannot be combined in this way. For example, you cannot free a pointer in CVI that you allocated using a different compiler.

 

When you compile a program in CVI you are using the CVI version of the ANSI C library. But when you compile it with MSVC, for example, you are using the ANSI C implementation from the VC runtime instead. Even though the two libraries have the same interface, you cannot use them interchangeably to access the same data.

 

If you really need to free a pointer in one dll that you allocated in a different dll, and you can't compile both dlls with the same compiler, then you should pass a function pointer for the free() function from one dll to the other, so that the dll that needs to free the pointer can free it by calling the function pointer, instead of calling free() directly. The same applies to your fopen/fgetc situation.

 

An even better (cleaner) way to handle this is to export from your support dll both an allocation function and a dispose function which your driver dll can then call whenever it's done using the data.

 

Hope this helps,

 

Luis

0 Kudos
Message 3 of 9
(10,899 Views)

Hi,

 

Any ideas why I can't free() a pointer from a DLL that was compiled with CVI?

 

mysupportlib.dll: (compiled with CVI)

void *func(void) { return malloc(100) };

 

mydriver.dll: (compiled with CVI)

void main(void) {

  void *x;

  x = func();

  free(x);  // Error here, unless malloc() is also in this function and we remove call to "func()"

}

 

It still looks like CVI is having a heap or separating heaps between DLLs, even though that's what TLS is supposed to be for. I really want to avoid having static libs for everything. 

 

Thanks,

Jason. 

0 Kudos
Message 4 of 9
(10,881 Views)

As LuisG wrote:


An even better (cleaner) way to handle this is to export from your support dll both an allocation function and a dispose function which your driver dll can then call whenever it's done using the data.


An application and a DLL loaded by that application - even if they are both CVI code - will maintain different instances of their run-time support library so they will have separate heaps for memory allocation.

 

If you really don't want to export a memory de-allocation function from your DLL - which would be unusual as this is by far the most common way of handling these circumstances - I suppose you could use the Windows SDK LocalAlloc()/LocalReAlloc() and LocalDiscard() functions instead of malloc()/realloc() and free(); these use the Windows heap which should be the same across application and DLL.

--
Martin
Certified CVI Developer
0 Kudos
Message 5 of 9
(10,862 Views)

Actually, if both dlls are compiled by CVI, this should work. I just tested it using one of the CVI examples (I modified samples\dll\basic\cvidl.cws), and I didn't get an error when I freed the pointer.

 

If you have a test program that reproduces this error, would you mind attaching it here so that we could investigate?

 

Having said that, Martin's point is still valid: from a design standpoint, it's definitely preferable to export a de-allocation function.

 

Thanks,

Luis

Message Edited by LuisG on 01-13-2009 11:10 AM
0 Kudos
Message 6 of 9
(10,848 Views)
Solution
Accepted by topic author jcurl
I think your two DLLs are using different 'Run-time support' options in the Target Settings, and so their memory management is being done in different CVI runtime DLLs. If you use the same 'Run-time support' option for both the allocator and deallocator, then the deallocation is going to work. But still, this is not very nice because in future, you may want to change the runtime support option, or use a different compiler, etc. So ideally, you should use one of the methods recommended by Luis.
0 Kudos
Message 7 of 9
(10,842 Views)

I'll give it a shot with the same run time (one was Full, the other was Instrument).

 

As for being unusual, the Unix world does this often enough. The first example I gave is the getline() function from GNU that will automatically malloc() or realloc() as required, leaving the calling application to free() the memory.

 

My drivers that I write as DLLs naturally enough do have their own deallocators as they're used by various other languages.  

0 Kudos
Message 8 of 9
(10,821 Views)

I have another experience in this same area.

 

I have a DLL that I made using CVI and I use Thread Local Storgae (TLS).

 

Part of the DLL_THREAD_ATTACH "reason" parameter when calling DllMain was doing a calloc to create the actual thread storage area, the pointer to which is managed as part of the TLS mechanism, which also requires a specialized alloc TlsAlloc() and free TlsFree().  You use TlsAlloc() to get an "index" for TLS, and you then separately alloc a memory block somewhere and put the pointer to it in the index that Win32 provided by the TlsAlloc() call. 

 

On a thread detach, I would free this allocated memory with a simple free(memorypointer) call.

 

However, CVI would claim a memory leak despite the free() call for both the TLSAlloc and the calloc memory blocks.

 

I changed the calloc calls to LocalAlloc and the frees to LocalFree and now CVI no longer claims there's a memory leak after program termination for either the index or the actual TLS memory block.

 

So I wonder what's really happening here - the calloc and free calls returned without error.

 

I saw that MSDN example for TLS used LocalAlloc and LocalFree so when in Rome ...

 

Menchar

0 Kudos
Message 9 of 9
(9,572 Views)