[Mono-list] InteropServices: DllNotFoundException...?

Jonathan Pryor jonpryor@vt.edu
Sun, 23 May 2004 10:19:22 -0400


On Sun, 2004-05-23 at 07:03, Simon Ask Ulsnes wrote:
> (sorry for top-posting, but)
> Thanks for your reply!
> As it turned out, I was calling a non-existant function in the GPGME API 
> that was referenced in the GPGME Info-pages, but was called something 
> else in gpgme.h.

That would be problematic...and somewhat surprising.  I'd expect to see
an EntryNotFoundException, not a DllNotFoundException, since the library
could be found but the function couldn't.  Weird.

> Converting from char* to string seems to work great, could you elaborate 
> on the memory issues that it might create?

That's because Mono, last I knew, was slightly buggy -- it doesn't
properly free the memory.  .NET does.

The deal is that class types such as System.String (as opposed to
structure types) are always heap allocated.  As such, to prevent memory
leaks when a class type is used as the return type of a function, two
things are done: 

  1: the data is marshaled from unmanaged to managed memory 
     ("marshaled" == "copied, with some potential data transformation 
     applied", such as converting Ansi strings to Unicode strings).

  2: the unmanaged memory is freed.

The problem is (2).  What memory manager is used?  If one memory manager
allocates memory and another memory manager frees it, the heap could
become corrupted.  This is bad.

.NET uses CoTaskMemAlloc() and CoTaskMemFree() as the memory manager
which crosses the managed/unmanaged boundary.  Mono will likely use
g_malloc() and g_free(), but last I knew memory wasn't actually being
freed.  This is probably why you're not seeing memory corruption. 
Instead, you'd be seeing memory leaks.

Again, see http://www.jprl.com/~jon/interop.html for more information.

> Also, Mono apparently can't convert from the C++ STL string to .NET 
> System.String - probably because Mono is written in C...

I sincerely doubt that Managed C++ permits such a conversion. 
Especially since the implementation of std::string is deliberately
unspecified.

> (I ended up using C++ simply because of the brilliant stream model, 
> which makes handling of strings (with stringstream) so much more 
> intuitive and easy).
> Luckily, string.c_str() converts from string to char*... ;-)

Unfortunately, no.  std::string::c_str() converts to a "const char*". 
Notice the "const"?  Furthermore, the memory returned by
std::string::c_str() is managed by the std::string instance.  So if you
attempted to manually free this memory (such as when the runtime
marshals the returned string...), you'd get *at best* a double delete,
and *at worst* heap corruption.

Furthermore, if you do something like this:

	const char*
	get_my_string()
	{
		std::string s ("this is my string");
		return s.c_str();
	}

You're *asking* for trouble, as the std::string destructor will free the
memory used to hold the string, so the string returned by
get_my_string() will be pointing to invalid memory.

> But yes, I hope this is something that will be improved. Currently, it 
> is extremely cumbersome to debug a C/C++ library through managed 
> applications.

So don't. :-)

Debug the unmanaged library in an unmanaged test application, and make
sure the unmanaged part *actually works*.  Once that works, *then*
introduce managed code.  To do otherwise is to greatly complicate your
life, as you won't know where the problem is occurring.

I would also suggest using valgrind, to help find memory leaks and
memory corruption in your unmanaged code.

 - Jon