1
votes

I'm building a plugin system with Delphi (some of you have been helping me with this task).

To search for the DLL files, I'm using a TSearchRec, which search's in the exe path for dll files, and then I'm using LoadLibrary to access them. Then, if a certain function is exposed (using GetProcAddress), I load it as a plugin. If not, FreeLibrary is executed, and moves on for the next file.

While testing, I noticed that when the TSearchRec found the "borlndmm.dll", which happened to be in that path, it loads, and searches for my plugin function, which of course is not found, but when if executes FreeLibrary, I get an Access Violation.

Other no-plugin dll's in the same path, like libmariadb.dll, are freed securely without errors.

Of course this is easily fixed, by having my plugin dll's in its own path, without any other dll files, which will be better even for performance reasons, as it doesn't have to load any library that it's not supposed to.

But I would like to understand why it happens. Any ideas?

Thank you Nuno Picado

2
Don't load random DLLS into your process. Really bad idea.David Heffernan
If you create a test application that does nothing else but call LoadLibrary on borlndmm.dll and then calls FreeLibrary, does this still happen? If so, please post the code used. If not, it's a problem isolated to your app itself. (I agree with @DavidHeffernan, BTW; loading random DLLs into your process is a terrible idea.)Ken White
Thank you David and Ken. I'll follow that advice!nunopicado
I've done a very similar project, doing almost exactly what you describe. The way I avoided loading DLL's that should never be loaded is by giving them a unique file extension. That way, you can only search for those files with whatever unique extension you decide to give them. These files should also presumably be in a folder of their own - not mixed with the rest of your program files, but in a subfolder.Jerry Dodge
Just a word of warning, you should never load DLL's without being 100% sure that you are in control of the contents. It's one of the easiest ways for viruses or malware to get up and running on a computer. I would add a configuration file that specifies which DLL's are included, change then name as Jerry suggested and then also include some sort of signature to make sure that it's your DLL.Graymatter

2 Answers

4
votes

That DLL implements a shared memory manager. It is designed to be used with load time linking only. It is loaded by the loader, and never unloaded until the process ends. Once it is loaded, it assumes responsibility for all future heap allocations and deallocations with the process. So it changes the behaviour of the host process. It cannot be loaded dynamically.

The moral of the story is not to load random DLLs into your process. Only load DLLs that either you or your program's users specifically ask to be loaded.

5
votes

The reason why you run into problems with some DLLS is because LoadLibrary executes code in the DLL it loads - specifically, the DLL's initialization code. In Delphi projects, this includes the unit initialization sections. In the case of borlandmm.dll, the dll initialization code inserts itself into your host exe process's runtime library, replacing your default memory manager with the memory manager in the DLL. This is not intended to be a reversible action - it can't remove itself in the DLL shutdown code (in part because DLL shutdown code is not guaranteed to execute in all circumstances).

So, be careful using LoadLibrary because you are basically executing arbitrary code before you even know what the DLL is. If you really must take a peek into a large number of arbitrary DLLs of unknown origin, a safer way would be to load the DLL as a resource image instead of as an executable image. This loads the file into memory but does not execute the DLL initialization code. See LoadLibraryEx() and the LOAD_LIBRARY_AS_IMAGE_RESOURCE flag.

As you mentioned in an earlier comment, there are a number of things you can do to reduce the number of DLLs you need to load to exactly the DLLs that the user/administrator wants your application to load, instead of loading everything you can find.

  1. Require the DLL file name have a custom extension or file name pattern. (Plugin*.mod for example)
  2. Only load DLLs from a special subdirectory. This works well with directory level access control, since on most systems bin directories are not writable by ordinary users. Someone would have to have admin rights to put a DLL into the special subdirectory.
  3. Only load DLL files that are named in a user-defined config file.
  4. Any combination of the above