C++ Lambdas: captured pointer to STL container changing address after pop? - c++

I'm trying to figure out why the following code breaks. After objects->pop(); is called in the lambda expression, the memory address of objects changes to 0xfeeefeee when debugging in Visual Studio. I can get around this issue by doing auto p = objects; before the pop, and then using p instead of objects in the second line of the lambda. However, I must be missing something fundamental here.
class Obj
{
public:
Obj(stack<shared_ptr<Obj>>* const objects) {
fun = [=] {
objects->pop(); // objects' address changed after this executes
objects->push(shared_ptr<Obj>(new Obj(objects)));
};
}
function<void(void)> fun;
};
int main()
{
stack<shared_ptr<Obj>> objects;
objects.push(shared_ptr<Obj>(new Obj(&objects)));
objects.top().get()->fun();
return 0;
}

What you are observing is undefined behavior.
The memory that the captured objects variable occupies is freed when you call objects->pop(); A good hint for this is the value it changes to: 0xFEEEFEEE. This magic number indicates freed memory.
Let's analyse what happens.
stack<shared_ptr<Obj>> objects;
objects.push(shared_ptr<Obj>(new Obj(&objects)));
A stack with shared_ptr's is created. Pushed on top of it is a new Obj instance, whose constructor argument is a pointer to our stack.
Obj(stack<shared_ptr<Obj>>* const objects) {
fun = [=] {
/* ... */
};
}
A function object is assigned a lambda, which captures the objects argument.
objects.top().get()->fun(); calls the function object:
objects->pop(); // objects' address changed after this executes
The top element of the stack that objects points to, is the Obj instance to which the fun object belongs. By popping it off, the only (and therefore last) instance of the shared_ptr holding a reference to it goes out of scope and frees the memory that it used. This includes the captured pointer to objects. In a debug build HeapFree sets it to 0xFEEEFEEE. In a release build anything could happen. After this point you're referencing released memory, which is undefined behavior.

When you call objeccts->pop(), the shared_ptr on top of the stack is destroyed. It is the last pointer to your instance of Obj, so that instance is destroyed. That instance contains the function object fun, so the function object is also destroyed.
Any access to the captured variables of the function object after this point is undefined behaviour, which first happens right on the next line.

For what I could deduce debugging your code, it seems to me that eventually you are doing pop on the top of stack, and with that you are trying to delete the pointer to the objects (the variable in the main function: by the way, you should rename that to eliminate confusion). As it is not on the heap, UB kicks in, and it gives (me) a segmentation fault.

Related

object created in function, is it saved on stack or on heap?

I am using c++ specifically:
when I create an object in a function, will this object be saved on the stack or on the heap?
reason I am asking is since I need to save a pointer to an object, and the only place the object can be created is within functions, so if I have a pointer to that object and the method finishes, the pointer might be pointing to garbage after.
--> if I add a pointer to the object to a list (which is a member of the class) and then the method finishes I might have the element in the list pointing to garbage.
so again - when the object is created in a method, is it saved on the stack (where it will be irrelevant after the function ends) or is it saved on the heap (therefore I can point to it without causing any issues..)?
example:
class blah{
private:
list<*blee> b;
public:
void addBlee() {
blee b;
blee* bp = &b;
list.push_front(bp);
}
}
you can ignore syntax issues -- the above is just to understand the concept and dilemma...
Thanks all!
Keep in mind following thing: the object is NEVER created in the heap (more correctly called 'dynamic storage' in C++) unless explicitly allocated on the heap using new operator or malloc variant.
Everything else is either stack/register (which in C++ should be called 'automatic storage') or a a statically allocated variable. An example of statically allocated variables are global variables in your program, variables local to the function which are declared static or static data members of classess.
You also need to very clear disntguish between a pointer and the object itself. In the following single line:
void foo() {
int* i = new int(42);
}
int is allocated dynamically (on the heap), while pointer to that allocated int has an automatic storage (stack or register). As a result, once foo() exits, the pointer is obliterated, but the dynamically allocated object remains without any means to access it. This is called classic memory leak.
Heap is the segment where dynamic memory allocation usually takes place so when ever you explicitly allocate memory to anything in a program you have given it memory from the heap segment.
Obj yo = new Obj; //something like this.
Stack is the another segment where automatic variables are stored, along with information that is saved each time a function is called.
Like when we declare:
*int* variable;
It will be on the stack and its validity is only till a particular function exits, whereas variables, objects etc on the heap remain there till main() finishes.
void addBlee() {
blee b; // this is created on the stack
blee* bp = &b;
list.push_front(bp); // this is a pointer to that object
} // after this brace b no longer exists, hence you have a dangling pointer
Do this instead:
list.push_front(new blee); // this is created on the heap and
// therefore it's lifetime is until you call
// delete on it`

Temporary variables created when using const reference

I am making some matrix class and I was wondering when a temporary object is created it is local to the function right? so it should get out of scope when function return but I don't know why that don't happen in this case I can use it after the function have returned.
Here is an example, this is the constructor:
int *data; //member of class
Matrix3(const int (&ar)[N*N])
{
data = const_cast<int*>(ar);
}
and here is how I use it:
Matrix3 m = { {1,2,3,4,5,6,6,6,6} };
Now I can still access that object from the destructor through the data pointer is this normal? the temporary variable is created on the heap then?!
The lifetime of a temporary ends at the semicolon of the statement or declaration that introduced it, not at the end of the function. (Otherwise, an innocuous loop could easily cause a stack overflow.)
If you use a reference to an object after its lifetime has ended (such as the array here), then you get undefined behavior. C++ does not keep track of dead objects in order to tell you when you are using one. You happen to find the information from the dead array. But something else could have reused the memory, or it could have been returned to the system and you could get a segfault.
Avoid dangling references and pointers. Do not suppose that if it works in a test-case, that it works in the field.
After your line executes, the temporary array is destroyed and the data pointer becomes invalid.
int *data; // is a member, so it goes out of scope when the object is destroyed
However, if you declared it in a function like this:
void someFunction() {
int *data;
}
// pointer is lost now and is inaccessible

Base and derived class allocation

In the code below, drvdCls derives from bseCls. This code compiles and runs as it is. I however find an issue here: newBse will get deallocated after Test() exits. Am I right?
bseCls* Test()
{
bseCls* newBse = new drvdCls();
drvdCls newDrvd;
newBse = &newDrvd;
return newBse;
}
The object originally pointed to by newBse will be leaked. When you assigned the address of newDrvd to newBse you are losing the pointer to the heap-allocated object, and you will not be able to delete it. This memory will be unusable until the process terminates.
Additionally, you are returning the address of a stack-allocated object as a pointer, which is bad for two reasons:
The object's destructor will have been called before the function returns, meaning you would be using a pointer to a destructed object.
The memory allocated for the object lives on the stack and will almost certainly be clobbered by future function calls. At that point, your pointer will be point at something that is not a bseCls, but you will be using it as though it were.
If you use the pointer returned by this function, you are invoking undefined behavior and your program has license to do anything.
No, it won't be automatically deallocated. Every call to new must be matched by a call to delete. But that's not the only problem with your code, you're also returning the address of a local variable from the function.
newBse = &newDrvd; // memory leak, pointer to previously allocated object is lost
return newBse; // newDrvd is destroyed when function exits, so returned
// pointer points to invalid memory
What you probably want to do is
bseCls* Test()
{
return new drvdCls();
}
Now the caller must call delete on the returned pointer after using it. What you should do is
std::unique_ptr<bseCls> Test()
{
return new drvdCls();
}
Now the allocated object will automatically be deleted when the returned unique_ptr goes out of scope.

Why does this work? This is a small example, but it even worked on a much more complex project

#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);
}
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.
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.
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.
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").
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.
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?

Storing a pointer to an object created in a method

Using C++:
I currently have a method in which if an event occurs an object is created, and a pointer to that object is stored in a vector of pointers to objects of that class. However, since objects are destroyed once the local scope ends, does this mean that the pointer I stored to the object in the vector is now null or undefined? If so, are there any general ways to get around this - I'm assuming the best way would be to allocate on the heap.
I ask this because when I try to access the vector and do operations on the contents I am getting odd behavior, and I'm not sure if this could be the cause or if it's something totally unrelated.
It depends on how you allocate the object. If you allocate the object as an auto variable, (i.e. on the stack), then any pointer to that object will become invalid once the object goes out of scope, and so dereferencing the pointer will lead to undefined behavior.
For example:
Object* pointer;
{
Object myobject;
pointer = &myobject;
}
pointer->doSomething(); // <--- INVALID! myobject is now out of scope
If, however, you allocate the object on the Heap, using the new operator, then the object will remain valid even after you exit the local scope. However, remember that there is no automatic garbage collection in C++, and so you must remember to delete the object or you will have a memory leak.
So if I understand correctly you have described the following scenario:
class MyClass
{
public:
int a;
SomeOtherClass b;
};
void Test()
{
std::vector<MyClass*> v;
for (int i=0; i < 10; ++i)
{
MyClass b;
v.push_back(&b);
}
// now v holds 10 items pointers to strange and scary places.
}
This is definitely bad.
There are two primary alternatives:
allocate the objects on the heap using new.
make the vector hold instances of MyClass (i.e. std::vector<MyClass>)
I generally prefer the second option when possible. This is because I don't have to worry about manually deallocating memory, the vector does it for me. It is also often more efficient. The only problem, is that I would have to be sure to create a copy constructor for MyClass. That means a constructor of the form MyClass(const MyClass& other) { ... }.
If you store a pointer to an object, and that object is destroyed (e.g. goes out of scope), that pointer will not be null, but if you try to use it you will get undefined behavior. So if one of the pointers in your vector points to a stack-allocated object, and that object goes out of scope, that pointer will become impossible to use safely. In particular, there's no way to tell whether a pointer points to a valid object or not; you just have to write your program in such a way that pointers never ever ever point to destroyed objects.
To get around this, you can use new to allocate space for your object on the heap. Then it won't be destroyed until you delete it. However, this takes a little care to get right as you have to make sure that your object isn't destroyed too early (leaving another 'dangling pointer' problem like the one you have now) or too late (creating a memory leak).
To get around that, the common approach in C++ is to use what's called (with varying degrees of accuracy) a smart pointer. If you're new to C++ you probably shouldn't worry about these yet, but if you're feeling ambitious (or frustrated with memory corruption bugs), check out shared_ptr from the Boost library.
If you have a local variable, such as an int counter, then it will be out of scope when you exit the function, but, unless you have a C++ with a garbage collector, then your pointer will be in scope, as you have some global vector that points to your object, as long as you did a new for the pointer.
I haven't seen a situation where I have done new and my memory was freed without me doing anything.
To check (in no particular order):
Did you hit an exception during construction of member objects whose pointers you store?
Do you have a null-pointer in the container that you dereference?
Are you using the vector object after it goes out of scope? (Looks unlikely, but I still have to ask.)
Are you cleaning up properly?
Here's a sample to help you along:
void SomeClass::Erase(std::vector<YourType*> &a)
{
for( size_t i = 0; i < a.size(); i++ ) delete a[i];
a.clear();
}