-
June 14th, 2007, 06:00 AM
#1
ESP not properly saved (DLL calling an exe's object function).
Hi gurus,
I'm stress-testing an application of mine.
This application is a service, so it has to be able to support quite a heavy loan of work.
It is installed and working fine at several customers. But one of them has very heavy traffic, so there it crashes once a day. The service automatically restarts but its clients have to reconnect and stuff, so the customer is not very happy... So that's why I'm stress-testing it, to see if I catch the bug.
The service is an exe file using a DLL, both are code of mine.
After half an hour of stress-testing I get this debug error:
File: i386\chkesp.c Line: 42 The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
The line where it crashes is within the DLL:
Code:
if (el) el->DeviceStatus((char *)(LPCTSTR)deviceId, numCallStates, csList);
deviceId is a valid CString (I can read its value is "30"), numCallStates is an int (I realize that it should be an unsigned int; but, should this be the problem?); its value is 1.
csList is:
Code:
long *csList = NULL;
(...)
csList = new long[1];
csList[0] = 0;
and, in fact, I can see its value is a pointer to a long with 0 value.
The "el" is a pointer to an object that was created at the exe file.
This is the prototype of the function at the DLL:
Code:
class CEventListener
{
public:
char clientId[128];
CRITICAL_SECTION *exitCs;
CEventListener() {};
virtual ~CEventListener() {};
virtual void LockRef() = 0;
virtual void UnlockRef() = 0;
(...)
virtual void DeviceStatus(char * deviceId, unsigned int numCalls, long *callStatusList) = 0;
(...)
};
And this is the prototype within the exe file:
Code:
class CClientThread : public CEventListener
{
public:
int Stop();
int Start();
int Run();
void LockRef();
void UnlockRef();
(...)
void DeviceStatus(char * deviceId, unsigned int numCalls, long *callStatusList);
(...)
CClientThread(SOCKET s, CServerThread *st);
virtual ~CClientThread();
CServerThread * server;
SOCKET clientSocket;
HANDLE hClientThread;
private:
(...)
};
Its implementation is, -within the exe file code-:
Code:
void CClientThread::DeviceStatus(char * deviceId, unsigned int numCalls, long *callStatusList)
{
CString msg;
CString cl, status;
for (UINT i = 0; i < numCalls; i++) {
status.Format("%ld", callStatusList[i]);
cl += status;
cl += ";";
}
msg.Format("[%s, %ld] <---- DeviceStatus(%s, %d, %s)",
clientId, clientSocket, deviceId, numCalls, cl);
g_logSystem.logNormal(2, msg);
msg.Format("24$%s$%d$%s", deviceId, numCalls, cl);
send(msg);
}
Calling convention in both project settings is __cdecl*
Please notice that this is not an exe calling a DLL function, but a DLL calling an exe's object function.
And also notice that it normally runs just fine. It is only when subjected to stress-testing, and after 20 or 30 minutes, when the error raises.
Any hints or clues on what may be happening? Why do I get that "ESP not properly saved" after hundreds of calls?
Thanks a lot!!
Ricardo Vázquez
Madrid, Spain.
-
June 14th, 2007, 06:43 AM
#2
Re: ESP not properly saved (DLL calling an exe's object function).
You may find interesting some more information about that el pointer:
As I told you it is a pointer to a CClientThread object (CEventListener interface).
Here you have the code where it is declared and set within the same function where the ESP error raises:
Code:
void CCTIALApp::notifySnapshotDevice(long invokeId, SnapshotDeviceResult *r, int nChId)
{
(...)
CEventListener *el = NULL;
(...)
bRes = operationsRunning.Lookup(invokeId, (void *&)el);
(...)
if (el) el->DeviceStatus((char *)(LPCTSTR)deviceId, numCallStates, csList);
(...)
}
-
June 14th, 2007, 07:10 AM
#3
Re: ESP not properly saved (DLL calling an exe's object function).
ESP is the stack pointer which, for some reason, is getting corrupted. Several things cause ESP to get manipulated but the most common ones are:-
1) Creating local variables.
2) Calling a function.
3) Returning from a function.
If you're certain that this isn't a problem with calling conventions, think about your local variables and/or function signatures. For example, it looks like you have two classes - CEventListener and operationsRunning. Is it possible that these are defined differently in 2 different header files? One of the headers is being used by the DLL and a different version is being used by the EXE? If that were the case, the DLL and EXE might not agree about the size of that particular class.
The same thing can happen with function signatures. From what you said, it sounds as if the DLL is calling a callback function within the EXE. But do they both agree about the return type? Is it possible that the DLL thinks that the callback returns void when it actually returns, say, int.
I realise that this example isn't relevant - but just as an example, the MFC message handler ON_MESSAGE needs a target function with this signature:-
Code:
LRESULT YourWindowClass::YourHandlerFunc(WPARAM, LPARAM);
If you create a handler function with the wrong type (or number) of parameters you'll get a compiler error. But my compiler will happily let me declare the ON_MESSAGE handler function with an incorrect return type - though of course, the program would eventually crash.
Don't know if that will help but those are the kinds of thing to look for.
"A problem well stated is a problem half solved.” - Charles F. Kettering
-
June 14th, 2007, 01:33 PM
#4
Re: ESP not properly saved (DLL calling an exe's object function).
Please notice that this is not an exe calling a DLL function, but a DLL calling an exe's object function.
And also notice that it normally runs just fine. It is only when subjected to stress-testing, and after 20 or 30 minutes, when the error raises.
Any hints or clues on what may be happening? Why do I get that "ESP not properly saved" after hundreds of calls?
The first thought crossed my mind was - some stack-allocated buffer overflow. Or (that seemed much worse) some wild pointer dereference.
Anyhow, it's with no doubt a case of a stack corruption.
Best regards,
Igor
-
June 15th, 2007, 06:47 AM
#5
Re: ESP not properly saved (DLL calling an exe's object function).
How bizarre...! In all my programming life, I've never seen this error - and yet it just happened to me, this morning!! Here's what it turned out to be:-
Code:
// Header file
class SourceFile
{
public:
SourceFile(std::string path);
virtual ~SourceFile();
};
class AudioFile : public SourceFile
{
public:
AudioFile(std::string path);
virtual ~AudioFile();
};
Code:
// CPP file
SourceFile::SourceFile(std::string path)
{
// Checks that the path is valid
// but doesn't do much else (doesn't
// allocate any memory, for example).
}
SourceFile::~SourceFile() // Note this destructor !
{
// Does nothing
}
AudioFile::AudioFile(std::string path)
: SourceFile(path)
{
// Create or open the file here
}
AudioFile::~AudioFile()
{
// Close the opened file
}
Note the destructor for the base class (SourceFile). If I comment out its body (leaving the declaration in its header file) the program builds without any error. But if the program creates an obect of type AudioFile (using new) and I later delete that object, I get the same ESP debug error that Xanblax found...
The correct versions of new and delete are being used.
I think someone a bit cleverer than me will have to explain it...!
"A problem well stated is a problem half solved.” - Charles F. Kettering
-
June 15th, 2007, 07:04 AM
#6
Re: ESP not properly saved (DLL calling an exe's object function).
What compiler do you use? I tried this in Studio2005 but got a "unresolved external symbol" linker error for SourceFile::~SourceFile(void)
-
June 15th, 2007, 08:27 AM
#7
Re: ESP not properly saved (DLL calling an exe's object function).
Well I'm baffled.... My compiler is VC++ 6.0 but I'm getting the same result as you now - I definitely had a situation this morning though where I could compile and link, with or without the destructor's body. I didn't need to do anything in the header file - just comment and un-comment the d'tor body...
I tried it several times before posting and the result was consistent every time. With the d'tor body included, everything worked as expected. And with it commented out, I got that error message.
Can't reproduce it now, though....
"A problem well stated is a problem half solved.” - Charles F. Kettering
-
June 15th, 2007, 11:29 AM
#8
Re: ESP not properly saved (DLL calling an exe's object function).
Things like that happen, I'm glad it's not just me.
It might be that this is good input for Xanblax anyway.
-
March 9th, 2010, 02:48 AM
#9
Re: ESP not properly saved (DLL calling an exe's object function).
you should be select related project properties and set _stdcall declaration method ...then this runtime error will not appear,,,,,,
-
March 1st, 2012, 10:53 PM
#10
Re: ESP not properly saved (DLL calling an exe's object function).
Try this way.
change the delegate declaration from
public delegate int SimpleDelegate(int x);
To:
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate int SimpleDelegate(int x);
-
March 2nd, 2012, 06:02 PM
#11
Re: ESP not properly saved (DLL calling an exe's object function).
Originally Posted by zreecu
Try this way.
change the delegate declaration from
public delegate int SimpleDelegate(int x);
To:
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate int SimpleDelegate(int x);
That might be good but the thread is about a year old and also in native C++ so your post is a bit misplaced.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|