#include <cstdio>
class baseclass
{
};
class derclass : public baseclass
{
public:
derclass(char* str)
{
mystr = str;
}
char* mystr;
};
baseclass* basec;
static void dostuff()
{
basec = (baseclass*)&derclass("wtf");
}
int main()
{
dostuff();
__asm // Added this after the answer found, it makes it fail
{
push 1
push 1
push 1
push 1
push 1
push 1
push 1
push 1
push 1
push 1
}
printf("%s", ((derclass*)basec)->mystr);
}
views:
220answers:
6Why does this work? This is a small example, but it even worked on a much more complex project.
The instance pointed to by basec
is a derclass, the casts just tell the compiler what to think of the pointer at any given moment.
Edit: strange that you can access the temporary later on. Does this still work if you allocate some other data on the stack?
Do you get a compiler warning from the (baseclass*)
cast?
basec = (baseclass*)&derclass("wtf");
Here a temporary object of derclass
is created and destructed immediately when ;
is encountered in dostuff()
function. Hence, your basec
pointer points to invalid object.
Note that basec = (baseclass*)&derclass("wtf");
causes undefined behavior to be invoked. The problem is that derclass("wtf")
creates a temporary object (of type derclass
) the &
in front of it will take the temporary object's address, which will then be assigned to basec
. Then, at the end of the full expression, the temporary object will be destroyed, leaving basec
with a pointer to a no longer existing object. When you later access this piece of memory (in (derclass*)basec)->mystr
) you are invoking undefined behavior.
Since it's the nature of undefined behavior to allow the program to do anything it pleases, your program might even work as if the object still existed. But it might as well crash, format your hard drive, or invoke nasty nasal demons on you.
What you would have to do is assign the address of an object to basec
which isn't destroyed as long as you use it. One way to do this would be to dynamically create an object: basec = new derclass("wtf")
.
As aJ notes, the temporary object you create is immediately destroyed. This doesn't exactly 'work': you're into undefined behaviour which may legally cause your monitor to catch on fire the next time you run it!
Hint: undefined behaviour - just say no.
Ugh. This is one of those "don't ever do this" examples. In dostuff
, you create a temporary of type derclass
, take its address, and manage to pass it outside of dostuff
(by assigning it to basec
). Once the line creating the temporary is finished, accessing it via that pointer yields undefined behavior. That it works (i.e. your program prints "wtf") is certainly platform dependent.
Why does it work in this specific instance? To explain this requires delving deeper than just C++. You create a temporary of type derclass
. Where is it stored? Probably it's stored as a very short lived temporary variable on the stack. You take it's address (an address on your stack), and store that.
Later, when you go to access it, you still have a pointer to that portion of your stack. Since nobody has since come along and reused that portion of the stack, the object's remnants are still there. Since the object's destructor doesn't do anything to wipe out the contents (which is, after all, just a pointer to "wtf" stored somewhere in your static data), you can still read it.
Try interjecting something which uses up a lot of stack between the dostuff
and printf
calls. Like, say, a call to a function which calculates factorial(10)
recursively. I'll bet that the printf
no longer works.
It creates the temporary variable on the stack because it's a local variable to the dostuff() function. Once the dostuff function exits, the stack rolls back possibly leaving the object on the memory stack exactly as it should be. Now your pointer is pointing to a spot on the stack that hopefully won't get clobbered by the call to printf when it passes in a pointer to stack memory that is no longer being used.
Usually stack that isn't being used isn't overwritten if you don't call other functions.
You could actually do some damage by calling a few functions, and then changing the value of mystr. The characters of text would then become part of the executable code. Hacker's dream.
Try something like this:
void breakStuff()
{
char dummy[3];
strcpy( dummy, "blahblahblahblahblah" );
int i = 7;
i = i + 8;
i = i + 22;
printf( "**%d**", i );
}
The strcpy will write PAST the local variable and overwrite the code. It'll die horribly. Good times, noodle salad.