tags:

views:

220

answers:

6
#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);
}
+1  A: 

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?

Robert Karl
+5  A: 
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.

aJ
ooooh.... i didn't notice that.
Robert Karl
Yeah, this is what I thought, but I can't get it to not work.
+1  A: 

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").

sbi
Yeah, I understand all that I just did it for clarity. See aJ's comment.
I have tried to add further explanations.
sbi
+2  A: 

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.

Pontus Gagge
+10  A: 

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.

Managu
You're certainly correct. I've modified the original example by making it fail through your instruction. What really surprised me and led me to create this small example was me doing this on a much larger scale worked, and I realized it shouldn't. I assumed the stack would have been sufficiently manipulated to rule out that possibility though, I was was wrong. I edited the original example to make it fail.
But that's the virtue of undefined behavior: It might do anything. It might even make the program work. But you'll never know.
sbi
A: 

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.

Kieveli