DLL-problem: Stack Corruption

Started by
7 comments, last by Necrarch 19 years, 7 months ago
Hello, I'm trying to write a DLL in which I want to put classes I use alot. I don't want any non-public methods or data members to be visible to my client applications. For learning/testing purposes, I have written a test class which contains one public method 'char* HelloWorld()' and one private data member 'char *data'. Upon class construction 'data' is set to "Hello World!". All the 'HelloWorld()' function does is returning the data pointer so it can be printed by my client application. When I link the lib/DLL to my client application, the data hiding seems to be working. I simply create an instance of the class, and call the 'HelloWorld()'-method. The only thing I see is the public method - the private data member is hidden. I have reached this by using an class interface / struct. All compiles well. When I run my client app in debug-mode and let it print the result from 'HelloWorld()', it prints it well, but then it gives the following message:
Quote: Debug Error! Run-Time Check Failure #2: Stack around the variable 't' was corrupted.
When I run it in release-mode no error message is given (obviously) but the text contains all kind of weird characters. Seems that the data of the class is pointing to somewhere it shouldn't. Here is the code: SVCORE.h (used by library code and client code)

#ifdef SVCORE_EXPORTS
    #define SVCORE_API __declspec(dllexport)
#else
    #define SVCORE_API __declspec(dllimport)
#endif


ITestClass.h (used by library code and client code)

struct SVCORE_API ITestClass
{
    virtual char*   HelloWorld(void) = 0;
};


SVTestClass.h (only used by client code)

#include <svcore/itestclass.h>

class SVCORE_API SVTestClass : public ITestClass
{
public:    
    char*   HelloWorld(void);    
};


SVTestClass.h (only used by library code)

//==============================================================
#include <svcore/itestclass.h>

class SVCORE_API SVTestClass : public ITestClass
{
public:
    SVTestClass(void);
    ~SVTestClass(void);

public:   
    char*   HelloWorld(void);    
    
private:
    char*   data;    
};


SVTestClass.cpp (only used by library code)

#include "svtestclass.h"

SVTestClass::SVTestClass(void)
{
    this->data = "Hello World!";
};

SVTestClass::~SVTestClass(void)
{
    this->data = NULL;
}    

char* SVTestClass::HelloWorld(void)
{
    return data;
}


And finally my client app

#include <stdio.h>
#include <svcore/svtestclass.h>

void main()
{
    SVTestClass t;
    printf("%s\n", t.HelloWorld());
}

Thus.. I have one general interface declaring which methods should be visible to the client app. In the library class I declare a data field, while the client isn't aware of it. What am I doing wrong? I DO need that data member in the class, but I DON'T want the client to be able to see or access it. Best wishes, and thanks for your help in advance, Necrarch
We are only alive because we dream %*
Advertisement
Quote:
Debug Error!
Run-Time Check Failure #2: Stack around the variable 't' was corrupted.
I don't see any of that code referencing a variable "t". You'll need to post that portion of the code as well.
Quote:Original post by Sneftel
Quote:
Debug Error!
Run-Time Check Failure #2: Stack around the variable 't' was corrupted.
I don't see any of that code referencing a variable "t". You'll need to post that portion of the code as well.


Sorry about that. I already edited my original post. Client app (with var 't') is included now. Please check again :)
We are only alive because we dream %*
What does sizeof(SVTestClass) return ?

As I can see, the client code allocates 4 bytes for t on the stack, that is because of the pointer to the vtable. In the dll code, however, you are accessing data, which is not in the reserved memory space.

When executing the code in debug mode, the debugger sees that the stack is corrupted after data was written. In release mode... noone knows.

You better use the same declaration for SVTestClass in dll code an client code.

If you do not want protected/private members in your declaration, create static factory methods that allocate the space on the heap. This way you avoid problems of this nature.
Quote:Original post by nmi
What does sizeof(SVTestClass) return ?

As I can see, the client code allocates 4 bytes for t on the stack, that is because of the pointer to the vtable. In the dll code, however, you are accessing data, which is not in the reserved memory space.

When executing the code in debug mode, the debugger sees that the stack is corrupted after data was written. In release mode... noone knows.

You better use the same declaration for SVTestClass in dll code an client code.

If you do not want protected/private members in your declaration, create static factory methods that allocate the space on the heap. This way you avoid problems of this nature.


I called the sizeof(SVTestClass) on the lib-version - it returned "8". When I called sizeof(SVTestClass) on the client-version it returned "4" (which is indeed obvious)

If this isn't the way to hide stuff, how could I do it then? You said something about creating static factory methods that allocate the space on the heap.... I'll start Googling and browsing the forums over here on it now. Does this mean, I can forget about the way I was doing it?
We are only alive because we dream %*
As you can see, the sizes don't match. If you create a local variable with a size of 4 bytes by
SVTestClass t;

and then access 8 bytes, you are definitively out of range.

What I would suggest is that you create the variable on the heap. Then it doesn't matter. Do it like this:

ITestClass.h:
struct SVCORE_API ITestClass{    virtual char*   HelloWorld(void) = 0;    static ITestClass* createITestClass();};


SVTestClass.h: (dll only)
//==============================================================#include <svcore/itestclass.h>class SVCORE_API SVTestClass : public ITestClass{public:    SVTestClass(void);    ~SVTestClass(void);public:       char*   HelloWorld(void);        private:    char*   data;    };


SVTestClass.cpp: (dll only)
#include "svtestclass.h"SVTestClass::SVTestClass(void){    this->data = "Hello World!";};SVTestClass::~SVTestClass(void){    this->data = NULL;}    char* SVTestClass::HelloWorld(void){    return data;}ITestClass* ITestClass::createITestClass(){    return new SVTestClass();}
Yeah, I see what you mean. Didn't think of that. But, that solution won't work for my design. Gonna be alot of classes around - eg. a texture manager class which provides access to texture classes.

I'd better go and find out how this 'data hiding' works.
Got some ideas or good links anyone?

Thanks anyway.
We are only alive because we dream %*
If you want to hide the data, you still have to let the compiler know of the size your class implementation has. You can trick the compiler by declaring a char array in your class to fill the remaining bytes.

In your test example above:
SVTestClass.h
#include <svcore/itestclass.h>class SVCORE_API SVTestClass : public ITestClass{public:        char*   HelloWorld(void);  // actually you don't need this line    char padding[4];};


Instead of 4 you should place some magical formula ;-)
Quote:Original post by nmi
If you want to hide the data, you still have to let the compiler know of the size your class implementation has. You can trick the compiler by declaring a char array in your class to fill the remaining bytes.

In your test example above:
SVTestClass.h
*** Source Snippet Removed ***

Instead of 4 you should place some magical formula ;-)


Won't work for me either. This would become really complicated when compiling on different platforms or using different compilers. Structure Alignment, packsize aso..

Anyway, This thread may be closed on my behalve. I made a followup to this one:
DLL Classes Hiding data members and methods for client - GameDev.Net Discussion Forums.

Thanks.
We are only alive because we dream %*

This topic is closed to new replies.

Advertisement