-
problem with freeing memory in dll
i have a dll that exports a class - it uses an abstract base class with pure virtual functions(defined in a header file), then a function to export it that returns a new object. insided the class is a 'release' function that deletes the object. now in another dll of mine, i dont do anything with the deconstructor, but in this one for some reason i have to have the same 'delete this' as i do in the release function or it crashes. now in the host application is where i get some sort of problem. note - it runs/finishes without error but some code isnt being exectued or something.
typedef IMyObj* (*PFNCreate)();
//main
char dllName[] = "dllname.dll";
HMODULE hmod = LoadLibrary(dllName);
if (!hmod)
{
cout << "error loading dll" << endl;
return 0;
}
PFNCreate pfnCreate = (PFNCreate)GetProcAddress(hmod, \
TEXT("CreateObject"));
IMyObject* obj = (pfnCreate)();
obj->function1();
//some code
cout << "??" << endl; //i get this outputted
obj->release();
delete obj;
FreeLibrary(hmod);
cout << "??"; //######## THIS DOESNT GET PRINTED
return 0;
thank you in advance, if more code is necessary to see what is going on let me know and ill post it.
-
Re: problem with freeing memory in dll
Quote:
Originally Posted by
rhboarder
obj->release();
delete obj;
Why are you using delete here? You said yourself that release() deletes the object.
-
Re: problem with freeing memory in dll
I'm a bit confused by your code.
You've gone through the effort of using dynamic access to the DLL. That is you used "LoadLibrary" and then "GetProcAddress" to find the function pointer to the "CreateObject" function.
But your code doesnt do the same for the "release function".
Is "release" a function pointer in the object?
If so, can you check to see that its getting fired correctly.
If not then could you explain how your code finds "release" but requires "GetProcAddress" to find "CreateObject"
Regards
-
Re: problem with freeing memory in dll
for the 1st reply: honestly i dont know why i needed it, i saw it done that way in a tutorial i read when learning how to export a class. and also the program crashes if i dont... 2nd reply - the release function is a class member in the class that's exported by CreateObject so you dont need to call getprocaddress for that. and i did check and it is getting fired correctly. here is a more complete code:
//#### header file for the dll
#if defined(DLL_EXPORT)
#define MYAPI __declspec(dllexport)
#else
#define MYAPI __declspec(dllimport)
#endif
class IMyObj //abstract interface
{
public:
//note - in sample tutorials ive read it says to have a deconstructor for the
// interface class but whenever i add 'virtual ~IMyObj()=0;' it doesnt compile.
virtual bool function1()=0;
virtual bool function2()=0;
virtual void release()=0;
};
extern "C" MYAPI IMyObj* __stdcall CreateObject();
//#####in dll(.cpp) file
#define DLL_EXPORT
#include "myheaderfile.h"
class myObj : public IMyObj
{
public:
~myObj()
{
cout << "deconstructor" << endl;
delete this; //as i said earlier in another app i wrote this line
//wasn't needed but now if i dont the program crashes
}
virtual bool function1()
{
//code
}
virtual void release()
{
delete this;
}
};
IMyObj* __stdcall CreateObject()
{
return new myObj;
}
//#### and then i include this header in the file that contains the code i previously posted.
-
Re: problem with freeing memory in dll
Quote:
Originally Posted by
rhboarder
and also the program crashes if i dont...
Any chance you could find what the error message is. If you're on windows vista you may have to go digging.
It just all seems that something is not happening as it appears. Deleting an object twice will cause an error and this code is deleting obj twice by what you're telling me:
Code:
obj->release();
delete obj;
If you like I could take a look at your full source code (dll as well) and have a dig into what's happening. Which compiler are you using?
-
Re: problem with freeing memory in dll
sorry bout the tags guys. i totally agree that deleting it twice should cause an error. but when i remove one i get another crash. For the compilor I'm using Borland 5.5 command line tools (bcc32). the error -
(in ollydbg) - access violation when writing to -
Code:
3250308F 8943 08 MOV DWORD PTR DS:[EBX+8],EAX
//and it says DS:[00000008] = ???
do you have an email address you'd like me send it to couling?
-
Re: problem with freeing memory in dll
I can PM you my email if you open your PM, or you can attach it as a zip on another message on this thread.
-
1 Attachment(s)
Re: problem with freeing memory in dll
here you go, i've attached a zip file containing the source files. thank you for taking a look at it.
-
Re: problem with freeing memory in dll
Quote:
Originally Posted by
rhboarder
here you go, i've attached a zip file containing the source files. thank you for taking a look at it.
The design is bad.
You are using two different heap managers, the DLL's and the apps. You can't call "new" in the DLL, and then use that same pointer in the call to "delete" in the application. The bottom line is -- unless your application and DLL are using the same heap manager, pointers returned by "new" from one DLL/app are incompatible with calls to "delete" in another DLL/app.
The DLL should be solely responsible for allocating and deallocating its own memory. If the DLL allocates, the DLL does the deallocation. The app shouldn't be in the business of knowing how the instance was created -- that detail is within the DLL.
Regards,
Paul McKenzie
-
Re: problem with freeing memory in dll
Quote:
Originally Posted by
rhboarder
for the 1st reply: honestly i dont know why i needed it, i saw it done that way in a tutorial i read when learning how to export a class. and also the program crashes if i dont...
The program will crash anyway!
Quote:
Originally Posted by
rhboarder
[code]
~myObj()
{
cout << "deconstructor" << endl;
delete this;
}
virtual void release()
{
delete this;
}
Think about what happens when you call release(). The delete will correctly call the destructor, but then the delete in the destructor will also call the destructor, an infinite loop!
So you need to remove the delete from the destructor and then find out the other reasons why the program crashes.
-
Re: problem with freeing memory in dll
so i removed the delete from the deconstructor and the 'delete obj' in the hosting application so now it is:
Code:
IMyObj = (pfnCreate)();
obj->function1();
cout << "????" << endl;
obj->realease();
FreeLibrary(hmod);
//this last cout gets printed but the program crashes right after
//it outputs it
cout << "??????";
return 0;
function1 is good, it executes perfectly, and i checked and release is getting fired... still unable to figure out what could be causing it to crash.
-
Re: problem with freeing memory in dll
Quote:
Originally Posted by
rhboarder
so i removed the delete from the deconstructor
The correct term is destructor, not deconstructor.
Also, please use code tags when posting code.
Quote:
still unable to figure out what could be causing it to crash.
Please repost the changed code for both the DLL and the application (and again, use code tags when posting code -- the code you posted is unformatted and almost impossible to read).
Regards,
Paul McKenzie
-
1 Attachment(s)
Re: problem with freeing memory in dll
Sorry that took me a while. Haven't used Borland in a while, so I needed to crank up my old pc. For your reference I'm using Borland C++ explorer 2005.
The code you attached was fine, I took out the two lines mentioned by Paul and Zaccheus and and there was little else wrong with it as such. That's not to say it didn't crash, just I don't think you'd done anything else particularly wrong.
The reason why putting "delete this;" in the destructor stopped it crashing was because (somehow) the resulting stack overflow it was causing was making it crash silently before it had chance for anything else to go wrong. And the line "delete spy" was doing nothing for me at all (different compiler version perhaps :confused: ).
So What's making it crash?
A little testing revealed that calling any virtual function in the DLL would cause a crash iif FreeLibrary was used to unload the dll. The crash actually occurred at the very end of your program (when main() called return 0; ). My only explanation is that its being caused by a little black magic going on in the way Borland calls virtual functions.
How to fix it?
you need to stop using vartual function calls across exe/dll boundaries or stop using Borland. When I compiled this with MinGW everything ran fine, when I removed all calls to virtual functions in the DLL in Borland it ran fine. When I had only one call to a virtual function that did nothing more than [ cout << "hello world" << endl; ] it crashed again.
Accessing DLLs in this way is really only necessary to load plug-in modules or to load a DLL after the program has started running. I was just wondering if you've been told to load a DLL this way by an article / tutorial of if you have a specific reason for doing it this way?
-
Re: problem with freeing memory in dll
yes it was from several articles i had read that made me think you had to do it that way. with the virtual functions, doesn't it have to be that way though because you change the implementation in the derived class? i've removed the virtual keywords. but now i get an error when compiling the application that loads the dll:
Code:
Error: Unresolved external 'IProcSpy::showProcesses(int __stdcall (*)(std::basic
_string<char, std::char_traits<char>, std::allocator<char> >))' referenced from
I:\TOOLS\BIN\WINPROCSPY.OBJ
Error: Unresolved external 'IProcSpy::release()' referenced from I:\TOOLS\BIN\WI
NPROCSPY.OBJ
here is the new code:
Code:
//header file
#ifndef PROCESSVIEWER_H
#define PROCESSVIEWER_H
#include <windows.h>
#include <string.h>
#include <tlhelp32.h>
#if defined(DLL_EXPORT)
#define MYAPI __declspec(dllexport)
#else
#define MYAPI __declspec(dllimport)
#endif
typedef BOOL (CALLBACK* PSENUMPROC_S)(string);
class IProcSpy
{
public:
bool showProcesses(PSENUMPROC_S);
void release();
};
extern "C" MYAPI IProcSpy* __stdcall CreateProcSpy();
#endif
//dll cpp file
#define DLL_EXPORT
#include "processViewer.h"
class procSpy : public IProcSpy
{
public:
~procSpy()
{
cout << "destructor" << endl;
}
bool showProcesses(PSENUMPROC_S cbkProc)
{
HANDLE snapshot = (0);
snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE) return false;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(snapshot, &pe32))
{
CloseHandle(snapshot);
return false;
}
ostringstream oss;
do
{
oss << pe32.szExeFile << ", PID = " << pe32.th32ProcessID;
(*cbkProc)(oss.str());
oss.str(std::string());
oss.seekp(0,std::ios_base::beg);
} while (Process32Next(snapshot, &pe32));
CloseHandle(snapshot);
return true;
}
void release()
{
delete this;
}
};
IProcSpy* __stdcall CreateProcSpy()
{
return new procSpy;
}
//in the main program
#include "processViewer.h"
typedef IProcSpy* (*PFNCreate)();
BOOL CALLBACK cbkProc(string);
int main()
{
char dllName[] = "processviewer.dll";
HMODULE hmod = LoadLibrary(dllName);
if (!hmod) return 0;
PFNCreate pfnCreate = (PFNCreate)GetProcAddress(hmod, \
TEXT("CreateProcSpy"));
IProcSpy* spy = (pfnCreate)();
spy->showProcesses(cbkProc);
spy->release();
FreeLibrary(hmod);
return 0;
}
BOOL CALLBACK cbkProc(string str)
{
cout << str << endl;
return TRUE;
}
thank you guys for all your help and your patience with me.
-
Re: problem with freeing memory in dll
Ah I see. That raises a number of issues.
Options for libraries:
- Keep the source in a folder and just add it every project
The easiest option, but it does increses build time and isn't the best way to share a library that's not open source. - Staticly compile it into a lib and add it to every project
It should be no more dificult than using a DLL. You get a single exe at the end. But you can't mix and match libraries without re-compiling your exe (unlike dlls) - Compile it into a dll
When you compile a dll, Borland will give you a lib as well. This contains stubs for all your functions. Each "stub" simply calls the aprorpriate function in the dll.
I want to use a dll... but how?
There are two options:
- By compiling the asociated lib into your exe (making it appear as if everything in the dll is in the lib). With this option windows will load the dll at the same time it loads your exe do all the work in connecting the two for you.
- By loading the dll after the program has started running using "LoadLibrary". This is only useful when you want to load a dll after the program has started running, or when you want to make your program load different dlls based on settings or a script.
If you're just starting out with dlls, I'd get to grips with option 1 first.
Do I need virtual functions?
No, not unless you'd need them anyway to achieve your goal in a standalone exe.
You can even replace virtual functions with function pointers in the object if virtual functions are going to cause problems.
Why do dlls get used?
- They're a reasonably reliable way to make redistributable code without giving out the source code.
- Advanced users can use them as a way to interface between code built with a number of different compilers.
- You can mix and match dlls after the exe has been compiled (as long as they have the same functions).
- You can make a program that accepts plugins.
- because they're cool! :cool:
Okay commercially they dont get used because they're cool, but particularly when learning to program it's allways fun to see what they're about.
Hope this is of some help
-
Re: problem with freeing memory in dll
Quote:
Originally Posted by
couling
you need to stop using vartual function calls across exe/dll boundaries or stop using Borland
Calling virtual functions across DLL boundaries is how COM works, any game which uses Direct X does it.
-
Re: problem with freeing memory in dll
ok so i think i've gotten it fully working without crashes now, although honestly i don't know why this works. ive defined the class member functions in the header as virtual, and then static loaded the lib file instead of using LoadLibrary with the dll. any thoughts on why using the static lib file is making the difference? i understand why/when to use a static lib but im just confused on why that would make it stop crashing compared to using LoadLibrary/FreeLibrary...
Thanks for all the replies and help, much appreciated. i was so surprised to get responses so fast you guys rock!
-
Re: problem with freeing memory in dll
As far as I can see, there's no reason for it to crash in the first place, just Borland doing something weird.
It makes sense for linking in the dll's lib file to have a difference because I found that removing "FreeLibrary" (really bad practice) stopped it. By linking in the lib file you delay the dll being freed from memory until your program has completely finished... it can't crash after that.
Quote:
Originally Posted by
Zaccheus
Calling virtual functions across DLL boundaries is how COM works, any game which uses Direct X does it.
I've never used com or direct X so I couldn't comment, but it raises one question to me:
How does that work between different compilers?
It's my understanding that anything object orientated cant be used as a DLL interface unless both DLL and calling code were written with the same compiler.
Far from least on the list of problems is that OO name mangling is completely non-standard. Are you sure it doesnt effectively just use function pointers?
-
Re: problem with freeing memory in dll
Quote:
Originally Posted by
couling
How does that work between different compilers?
It's my understanding that anything object orientated cant be used as a DLL interface unless both DLL and calling code were written with the same compiler.
Or unless both follow the exact same standard.
Microsoft have specified how COM interfaces are implemented, so any compiler vendor can ensure that their compiler is compatible.
And yes internally it does end up being just function pointers. You can even call COM objects from C using structures containing function pointers.
For example, here's a super simple COM interface:
Code:
struct IDendros0200Content1 : public IUnknown
{
virtual HRESULT STDMETHODCALLTYPE get_Parent(IDendros0200Element1 **theParent) = 0;
};
The same can be expressed in C as:
Code:
struct IDendros0200Content1Vtbl
{
// IUnknown base class virtual functions
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(IDendros0200Content1 * This, REFIID riid, void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(IDendros0200Content1 * This);
ULONG ( STDMETHODCALLTYPE *Release )(IDendros0200Content1 * This);
// IDendros0200Content1 virtual functions
HRESULT ( STDMETHODCALLTYPE *get_Parent )(IDendros0200Content1 * This, IDendros0200Element1 **theParent);
};
struct IDendros0200Content1
{
struct IDendros0200Content1Vtbl* lpVtbl;
};
-
Re: problem with freeing memory in dll
You've sort of undone your own statement there by demonstrating that not all COM programs use virtual functions. The fact that some do is a hack in the compiler. A reasonably elagent hack I'll grant, but you cant garuntee every compiler has it.
In implamentation outside COM development, compilers have a myriad of ways to implament virtual functions and the way any particular compiler does it is usually unclear to a developer.
-
Re: problem with freeing memory in dll
It's not a hack, just a way of implementing virtual functions in plain C which follows the documented structure used by COM.
The point of my original statement was that using virtual functions of objects which came from another DLL is not unusual in Windows programming. No matter how you use it, via C++ virtual functions which conform to COM's standard, or via C structures which conform to COM's standard, games which use Direct X do call the functions exposed from another DLL via that mechanism.
For reference, here are two very good articles about COM:
http://www.codeproject.com/KB/COM/comintro.aspx
http://www.codeproject.com/KB/COM/comintro2.aspx
-
Re: problem with freeing memory in dll
You missed my point.
The plain C isn't a hack. Its just plain old callback functions as they existed before the days of OO. Its explicit and doesnt rely on the specific compiler to make it work so if you took it to any other windows C++ compiler, the code would still run.
The hack is a C++ compiler which implaments virtual functions in a way that conveniently mimics the model of callback functions in exactly the way that's expected by the COM document structure. From the point of view of a C++ compiler, it has never been standardised how the "this" pointer should be passed, or where the callback function pointers for an object are stored. It's a Microsoft hack.
Some compilers don't even store the function pointers inside the object!
Take Borland, the compiler this discussion thread started with. With borland compile the following code:
Code:
#include <iostream>
using namespace std;
class X {
virtual int foo() = 0;
};
class Y {
virtual int foo() = 0;
virtual int bar() = 0;
};
int main(int argc, char* argv[])
{
cout << sizeof(X) << ", " << sizeof(Y);
return 0;
}
The resulting program will print "4, 4".
If this was to compile things in such a way as to be compatible with COM it would have to print "4, 8" because it would have to allocate space for both foo() and bar().
Unless Borland can somehow magically detect that you're compiling a DLL for use with COM, then using virtual functions wont work!
Hope this clarifies things a little.
-
Re: problem with freeing memory in dll
Quote:
Originally Posted by
couling
The hack is a C++ compiler which implaments virtual functions in a way that conveniently mimics the model of callback functions in exactly the way that's expected by the COM document structure.
Quick note; As far as I know, it was the other way around: Microsoft based the COM structure on how virtual funtions were implemented in their Visual C++ compiler. Not that this matters.
From the point of view of an ANSI C++ compiler, I agree with you. According to the ANSI/ISO standard, any C++ compiler has huge freedom to implement function calls, structure layouts, and type sizes in different ways.
Having said that, it would be impossible to call any Windows API functions if compilers written for Windows didn't follow certain OS specific standards. The __stdcall calling convention is an example, and the internal layout of the C structures used by the Windows API has to be implemented the same for every compiler. For Windows C++ compilers to also follow Microsoft's way of implementing virtual functions is not much different.
Quote:
Originally Posted by
couling
Code:
#include <iostream>
using namespace std;
class X {
virtual int foo() = 0;
};
class Y {
virtual int foo() = 0;
virtual int bar() = 0;
};
int main(int argc, char* argv[])
{
cout << sizeof(X) << ", " << sizeof(Y);
return 0;
}
The resulting program will print "4, 4".
That is correct. Look at the code I posted again. The interface IDendros0200Content1 has a pointer to the virtual function table. No matter how many functions there are, the interface will always have the same size.
-
Re: problem with freeing memory in dll
Hmm, for some reason I read it as being inline rather than as a pointer to the vtable. Not sure what I was drinking to make me see that :sick:. That kinda makes my last two posts make a lot less sense since I've long been aware of the vtable technique.
Still its an interesting point which appears to need a lot more reading on my part. Up until now all the infomation I've read suggests never using object orientated stuff in a dll interface when working across compilers due to a lack of standardisation. This is the main reason given for compiler vendors making no attempt to standardise name mangling as an attempt to discourage programmers doing so.
Also I'd love to know what Borland was doing to mess up virtual functions with dynamically loaded Dlls.
-
Re: problem with freeing memory in dll
Quote:
Originally Posted by
couling
Up until now all the infomation I've read suggests never using object orientated stuff in a dll interface when working across compilers due to a lack of standardisation.
Generally speaking, I absolutely agree. Never using 'new' in one DLL and 'delete' in another, for example.
It is probably only due to the widespread use of COM that the virtual table implementation became standardised on Windows at all (note this only applies to single inheritance!).
I would have preferred a vendorspecific keyword ( struct __interface IMyInterface {}; ) to be used when declaring such interfaces, to make it explicit, just like __stdcall.
-
Re: problem with freeing memory in dll
Quote:
Originally Posted by
couling
So What's making it crash?
A little testing revealed that calling any virtual function in the DLL would cause a crash iif FreeLibrary was used to unload the dll. The crash actually occurred at the very end of your program (when main() called return 0; ). My only explanation is that its being caused by a little black magic going on in the way Borland calls virtual functions.
I don't have a Borland compiler anymore otherwise I'd try this myself ...
Does the program still crash if we add the following function to the DLL and call that instead of calling release() ? Also release() should be declared __stdcall just to be safe.
Code:
extern "C" void MYAPI __stdcall DeleteDllObject(DllObjectParent* obj)
{
delete dynamic_cast<DllObject*>(obj);
}
I'm wondering if a moderator should move this thread to the Windows API section.
-
Re: problem with freeing memory in dll
Apologies for my mis information guys. Seems that using Dynamic load DLLs with borland is pretty much foo-bared up. Just I was unlucky to get ~10 tests that ran fine, the only feature obveously different between those that did and those that didn't was the virutal function thing.
The more tests I run the more I get what appear to be random crashes. Changing insugnificant parts of the code just cause it to a crash. :sick:
-
Re: problem with freeing memory in dll
to that last post by couling, now you know what i was going through lol.
here's a link to a site i had found about exporting classes from a dll.
http://www.codeproject.com/KB/cpp/ho...p_classes.aspx
one other question for you guys, what do you suggest if i don't want to use the
lib file like if me/someone else want to use it but only has the header file and the dll?
i never really found a fix for that..
if i can tonight or tomorrow ill try out what zaccheus mentioned. i saw that actually on the tutorial i linked to above, under the heading 'The C Language Approach' but as far as i can tell the example didn't use it on the part under 'C++ Mature Approach'
-
Re: problem with freeing memory in dll
Most compiler suits come with a program to automatically generate .lib files from the dll (This is called "implib" under borland). With some compilers such as MinGW you can pass the Dll in as a command line option and it just implies the infomation that the .lib would provide. Usually its easier to distribute the .lib file with the dll if you can tho.
Edit: Oh, implib can also create a .lib from a .def text file, so you can control it if you're getting problems automatically implying from a dll
-
Re: problem with freeing memory in dll
thanks couling. two things: one method that works is as zaccheus said using another external
function in the dll to delete the object. secondly, and this actually fixed my original
problem with LoadLibrary/FreeLibrary. I was looking at the documentation for
FreeLibrary and it says when it is called it will call DllMain. i didn't previously have
that so i added the following -
Code:
BOOL WINAPI DllEntryPoint(HINSTANCE, DWORD, LPVOID)
{
return TRUE;
}
-
Re: problem with freeing memory in dll
Quote:
Originally Posted by
rhboarder
one method that works is as zaccheus said using another external function in the dll to delete the object.
I stated the same thing back in post #9, but for some reason, you just glossed over it.
In general, the only memory allocation functions that work across compilers are the OS memory allocation functions. In Windows, you have GlobalAlloc(), HeapAlloc(), etc. These set of functions are guaranteed to be compatible across compilers, and even across different computer languages that have access to the Windows API functions.
As far as Borland goes, I have a DLL written in Visual C++, and Borland compilers use it with no problems whatsoever. The DLL does as I stated -- it allocates and deallocates its own memory when it comes to "new" and "delete". In addition, any memory that the DLL wants to give to the app to handle for themselves, that memory is obtained using the OS functions, as mentioned previously.
Quote:
secondly, and this actually fixed my original
problem with LoadLibrary/FreeLibrary. I was looking at the documentation for FreeLibrary and it says when it is called it will call DllMain. i didn't previously have that
That shouldn't make any difference. If your DLL does not have a DllMain, then one is automatically added that does the default (return TRUE). So I don't know if you really fixed anything or your compiler is seriously broken in terms of producing valid DLL's.
Regards,
Paul McKenzie
-
Re: problem with freeing memory in dll
Quote:
Originally Posted by
rhboarder
That's a great article! :cool:
-
Re: problem with freeing memory in dll
sorry paul, i mustn't have seen that post. i thought the same thing that it shouldn't make a difference, so maybe it is my compiler.
-
Re: problem with freeing memory in dll
For your CreateObject to work correctly all class methods that you wish to use in the exe that are defined in the parent have to be virtual. This also includes the destructor. The reason for this is that the object returned via Createobject has a virtual function table which will give you access to the methods without a GetProcAddress
-
Re: problem with freeing memory in dll
A destructor only needs to be virtual if you want to call delete on a base class pointer.
-
Re: problem with freeing memory in dll
For the release to be implemented in the dll it would be doing a delete on the base class.
-
Re: problem with freeing memory in dll
Nope, release is always implemented in the most derived class.