We received code from a subcontractor that does essentially the following:
class Callable
{
public:
void operator()(int x)
{
printf("x = %d\n", x);
}
};
template<typename T>
class UsesTheCallable
{
public:
UsesTheCallable(T callable) :
m_callable(NULL)
{
m_callable = &callable;
}
~UsesTheCallable() {}
void call() { (*m_callable)(5); }
private:
T* m_callable;
};
This strikes me as being undefined code...they pass in the T by value to the UsesTheCallable constructor then assign the m_callable member to the address of the argument, which should go out of scope at tne end of the constructor, and so anytime I call UsesTheCallable::call(), I'm acting on an object that no longer exists.
So I tried it with this main method:
int main(int, char**)
{
UsesTheCallable<Callable>* u = NULL;
{
Callable c;
u = new UsesTheCallable<Callable>(c);
}
u->call();
delete u;
return 0;
}
I make sure that the Callable object goes out of scope before I call UsesTheCallable::call(), so I should be calling the function on memory that I don't actually own at that point. But the code works, and Valgrind reports no memory errors, even if I put some member data into the Callable class and make the operator() function act on that member data.
Am I correct that this code is undefined behavior? Is there any difference in the "defined-ness" of this code based on whether or not Callable has member data (e.g. a private int variable or something)?
Yes this is undefined behavior. After the closing brace of the constructor callable is destroyed and you have a dangling pointer.
The reason you are not seeing adverse effects is that you really aren't using the instance after it goes out of scope. The function call operator is stateless so it is not trying to access the memory that it no longer owns.
If we add some state to the callable like
class Callable
{
int foo;
public:
Callable (int foo = 20) : foo(foo) {}
void operator()(int x)
{
printf("x = %d\n", x*foo);
}
};
and then we use
int main()
{
UsesTheCallable<Callable>* u = NULL;
{
Callable c(50);
u = new UsesTheCallable<Callable>(c);
}
u->call();
delete u;
return 0;
}
Then you could see this bad behavior. In that run it outputs x = 772773112 which is not correct.
m_callable = &callable;
Am I correct that this code is undefined behavior?
Yes, this is bullsh!t, for the reason you give.
But the code works
Yeah, well, that's what happens with UB…
and Valgrind reports no memory errors
…particularly when the memory you're operating on still "belongs" to your process. There's nothing for Valgrind to detect here; it doesn't validate C++ scopes, only "physical"† memory accesses. And the program doesn't crash because nothing's yet had much of a chance to mangle the memory that used to be taken up by c.
† "Physical" in the sense that I'm referring to the OS and its memory management, rather than C++'s abstract concepts. It could actually be virtual memory or whatever.
Related
Is the following code (func1()) correct if it has to return i? I remember reading somewhere that there is a problem when returning a reference to a local variable. How is it different from func2()?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
This code snippet:
int& func1()
{
int i;
i = 1;
return i;
}
will not work because you're returning an alias (a reference) to an object with a lifetime limited to the scope of the function call. That means once func1() returns, int i dies, making the reference returned from the function worthless because it now refers to an object that doesn't exist.
int main()
{
int& p = func1();
/* p is garbage */
}
The second version does work because the variable is allocated on the free store, which is not bound to the lifetime of the function call. However, you are responsible for deleteing the allocated int.
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
int main()
{
int* p = func2();
/* pointee still exists */
delete p; // get rid of it
}
Typically you would wrap the pointer in some RAII class and/or a factory function so you don't have to delete it yourself.
In either case, you can just return the value itself (although I realize the example you provided was probably contrived):
int func3()
{
return 1;
}
int main()
{
int v = func3();
// do whatever you want with the returned value
}
Note that it's perfectly fine to return big objects the same way func3() returns primitive values because just about every compiler nowadays implements some form of return value optimization:
class big_object
{
public:
big_object(/* constructor arguments */);
~big_object();
big_object(const big_object& rhs);
big_object& operator=(const big_object& rhs);
/* public methods */
private:
/* data members */
};
big_object func4()
{
return big_object(/* constructor arguments */);
}
int main()
{
// no copy is actually made, if your compiler supports RVO
big_object o = func4();
}
Interestingly, binding a temporary to a const reference is perfectly legal C++.
int main()
{
// This works! The returned temporary will last as long as the reference exists
const big_object& o = func4();
// This does *not* work! It's not legal C++ because reference is not const.
// big_object& o = func4();
}
A local variable is memory on the stack, and that memory is not automatically invalidated when you go out of scope. From a function deeper nested (higher on the stack in memory), it’s perfectly safe to access this memory.
Once the function returns and ends though, things get dangerous.
Usually the memory is not deleted or overwritten when you return, meaning the memory at that address is still containing your data - the pointer seems valid.
Until another function builds up the stack and overwrites it.
This is why this can work for a while - and then suddenly cease to function after one particularly deeply nested set of functions, or a function with really huge sized or many local objects, reaches that stack-memory again.
It even can happen that you reach the same program part again, and overwrite your old local function variable with the new function variable. All this is very dangerous and should be heavily discouraged.
Do not use pointers to local objects!
A good thing to remember are these simple rules, and they apply to both parameters and return types...
Value - makes a copy of the item in question.
Pointer - refers to the address of the item in question.
Reference - is literally the item in question.
There is a time and place for each, so make sure you get to know them. Local variables, as you've shown here, are just that, limited to the time they are locally alive in the function scope. In your example having a return type of int* and returning &i would have been equally incorrect. You would be better off in that case doing this...
void func1(int& oValue)
{
oValue = 1;
}
Doing so would directly change the value of your passed in parameter. Whereas this code...
void func1(int oValue)
{
oValue = 1;
}
would not. It would just change the value of oValue local to the function call. The reason for this is because you'd actually be changing just a "local" copy of oValue, and not oValue itself.
Title may be misleading, not sure how to explain this but I'll provide an example.
So I have this structures:
struct mom {
public:
static constexpr auto create(int i) {
return a(i);
}
struct a {
int* m_a;
constexpr a(int i) : m_a(&i) {
change();
}
constexpr void change(void) {
*m_a += 100;
}
struct b {
public:
static int get(a* import) {
int* arr = new int[10];
arr[1] = *import->m_a;
return arr[1];
}
};
};
};
And I call it like this:
printf("%d", mom::a::b::get(&(mom::create(10))));
It is supposed to add 100 the 10 (or any other value you give it) at compile time, then at runtime to store it into a dynamic array and return it to you.
This code is almost exact to my project, but it has a problem: instead of adding 100 to the value, it returns a random big number (-95321314). I tried debugging it and it is all fine until I call the get() function in which I have no idea what is happening that causes this
any ideas?
The problem is m_a is a pointer to a temporary, as soon the stack unwinds further usage of that temporary is undefined.
Specifically, the call to mom::create(10) returns a struct a, whose member m_a is no longer pointing to a valid region of memory. Subsequent usage of that member will be undefined (e.g. the copy into b's array in get())
A simple "fix" would be to change m_a(&i) -> m_a(new int(i)), although note that this introduces a memory leak and changes the memory layout entirely. Since it's not clear to me what your design goals are, it's a reasonable alternative to get things "working".
Is the following code (func1()) correct if it has to return i? I remember reading somewhere that there is a problem when returning a reference to a local variable. How is it different from func2()?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
This code snippet:
int& func1()
{
int i;
i = 1;
return i;
}
will not work because you're returning an alias (a reference) to an object with a lifetime limited to the scope of the function call. That means once func1() returns, int i dies, making the reference returned from the function worthless because it now refers to an object that doesn't exist.
int main()
{
int& p = func1();
/* p is garbage */
}
The second version does work because the variable is allocated on the free store, which is not bound to the lifetime of the function call. However, you are responsible for deleteing the allocated int.
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
int main()
{
int* p = func2();
/* pointee still exists */
delete p; // get rid of it
}
Typically you would wrap the pointer in some RAII class and/or a factory function so you don't have to delete it yourself.
In either case, you can just return the value itself (although I realize the example you provided was probably contrived):
int func3()
{
return 1;
}
int main()
{
int v = func3();
// do whatever you want with the returned value
}
Note that it's perfectly fine to return big objects the same way func3() returns primitive values because just about every compiler nowadays implements some form of return value optimization:
class big_object
{
public:
big_object(/* constructor arguments */);
~big_object();
big_object(const big_object& rhs);
big_object& operator=(const big_object& rhs);
/* public methods */
private:
/* data members */
};
big_object func4()
{
return big_object(/* constructor arguments */);
}
int main()
{
// no copy is actually made, if your compiler supports RVO
big_object o = func4();
}
Interestingly, binding a temporary to a const reference is perfectly legal C++.
int main()
{
// This works! The returned temporary will last as long as the reference exists
const big_object& o = func4();
// This does *not* work! It's not legal C++ because reference is not const.
// big_object& o = func4();
}
A local variable is memory on the stack, and that memory is not automatically invalidated when you go out of scope. From a function deeper nested (higher on the stack in memory), it’s perfectly safe to access this memory.
Once the function returns and ends though, things get dangerous.
Usually the memory is not deleted or overwritten when you return, meaning the memory at that address is still containing your data - the pointer seems valid.
Until another function builds up the stack and overwrites it.
This is why this can work for a while - and then suddenly cease to function after one particularly deeply nested set of functions, or a function with really huge sized or many local objects, reaches that stack-memory again.
It even can happen that you reach the same program part again, and overwrite your old local function variable with the new function variable. All this is very dangerous and should be heavily discouraged.
Do not use pointers to local objects!
A good thing to remember are these simple rules, and they apply to both parameters and return types...
Value - makes a copy of the item in question.
Pointer - refers to the address of the item in question.
Reference - is literally the item in question.
There is a time and place for each, so make sure you get to know them. Local variables, as you've shown here, are just that, limited to the time they are locally alive in the function scope. In your example having a return type of int* and returning &i would have been equally incorrect. You would be better off in that case doing this...
void func1(int& oValue)
{
oValue = 1;
}
Doing so would directly change the value of your passed in parameter. Whereas this code...
void func1(int oValue)
{
oValue = 1;
}
would not. It would just change the value of oValue local to the function call. The reason for this is because you'd actually be changing just a "local" copy of oValue, and not oValue itself.
Is the following code (func1()) correct if it has to return i? I remember reading somewhere that there is a problem when returning a reference to a local variable. How is it different from func2()?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
This code snippet:
int& func1()
{
int i;
i = 1;
return i;
}
will not work because you're returning an alias (a reference) to an object with a lifetime limited to the scope of the function call. That means once func1() returns, int i dies, making the reference returned from the function worthless because it now refers to an object that doesn't exist.
int main()
{
int& p = func1();
/* p is garbage */
}
The second version does work because the variable is allocated on the free store, which is not bound to the lifetime of the function call. However, you are responsible for deleteing the allocated int.
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
int main()
{
int* p = func2();
/* pointee still exists */
delete p; // get rid of it
}
Typically you would wrap the pointer in some RAII class and/or a factory function so you don't have to delete it yourself.
In either case, you can just return the value itself (although I realize the example you provided was probably contrived):
int func3()
{
return 1;
}
int main()
{
int v = func3();
// do whatever you want with the returned value
}
Note that it's perfectly fine to return big objects the same way func3() returns primitive values because just about every compiler nowadays implements some form of return value optimization:
class big_object
{
public:
big_object(/* constructor arguments */);
~big_object();
big_object(const big_object& rhs);
big_object& operator=(const big_object& rhs);
/* public methods */
private:
/* data members */
};
big_object func4()
{
return big_object(/* constructor arguments */);
}
int main()
{
// no copy is actually made, if your compiler supports RVO
big_object o = func4();
}
Interestingly, binding a temporary to a const reference is perfectly legal C++.
int main()
{
// This works! The returned temporary will last as long as the reference exists
const big_object& o = func4();
// This does *not* work! It's not legal C++ because reference is not const.
// big_object& o = func4();
}
A local variable is memory on the stack, and that memory is not automatically invalidated when you go out of scope. From a function deeper nested (higher on the stack in memory), it’s perfectly safe to access this memory.
Once the function returns and ends though, things get dangerous.
Usually the memory is not deleted or overwritten when you return, meaning the memory at that address is still containing your data - the pointer seems valid.
Until another function builds up the stack and overwrites it.
This is why this can work for a while - and then suddenly cease to function after one particularly deeply nested set of functions, or a function with really huge sized or many local objects, reaches that stack-memory again.
It even can happen that you reach the same program part again, and overwrite your old local function variable with the new function variable. All this is very dangerous and should be heavily discouraged.
Do not use pointers to local objects!
A good thing to remember are these simple rules, and they apply to both parameters and return types...
Value - makes a copy of the item in question.
Pointer - refers to the address of the item in question.
Reference - is literally the item in question.
There is a time and place for each, so make sure you get to know them. Local variables, as you've shown here, are just that, limited to the time they are locally alive in the function scope. In your example having a return type of int* and returning &i would have been equally incorrect. You would be better off in that case doing this...
void func1(int& oValue)
{
oValue = 1;
}
Doing so would directly change the value of your passed in parameter. Whereas this code...
void func1(int oValue)
{
oValue = 1;
}
would not. It would just change the value of oValue local to the function call. The reason for this is because you'd actually be changing just a "local" copy of oValue, and not oValue itself.
Is the following code (func1()) correct if it has to return i? I remember reading somewhere that there is a problem when returning a reference to a local variable. How is it different from func2()?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
This code snippet:
int& func1()
{
int i;
i = 1;
return i;
}
will not work because you're returning an alias (a reference) to an object with a lifetime limited to the scope of the function call. That means once func1() returns, int i dies, making the reference returned from the function worthless because it now refers to an object that doesn't exist.
int main()
{
int& p = func1();
/* p is garbage */
}
The second version does work because the variable is allocated on the free store, which is not bound to the lifetime of the function call. However, you are responsible for deleteing the allocated int.
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
int main()
{
int* p = func2();
/* pointee still exists */
delete p; // get rid of it
}
Typically you would wrap the pointer in some RAII class and/or a factory function so you don't have to delete it yourself.
In either case, you can just return the value itself (although I realize the example you provided was probably contrived):
int func3()
{
return 1;
}
int main()
{
int v = func3();
// do whatever you want with the returned value
}
Note that it's perfectly fine to return big objects the same way func3() returns primitive values because just about every compiler nowadays implements some form of return value optimization:
class big_object
{
public:
big_object(/* constructor arguments */);
~big_object();
big_object(const big_object& rhs);
big_object& operator=(const big_object& rhs);
/* public methods */
private:
/* data members */
};
big_object func4()
{
return big_object(/* constructor arguments */);
}
int main()
{
// no copy is actually made, if your compiler supports RVO
big_object o = func4();
}
Interestingly, binding a temporary to a const reference is perfectly legal C++.
int main()
{
// This works! The returned temporary will last as long as the reference exists
const big_object& o = func4();
// This does *not* work! It's not legal C++ because reference is not const.
// big_object& o = func4();
}
A local variable is memory on the stack, and that memory is not automatically invalidated when you go out of scope. From a function deeper nested (higher on the stack in memory), it’s perfectly safe to access this memory.
Once the function returns and ends though, things get dangerous.
Usually the memory is not deleted or overwritten when you return, meaning the memory at that address is still containing your data - the pointer seems valid.
Until another function builds up the stack and overwrites it.
This is why this can work for a while - and then suddenly cease to function after one particularly deeply nested set of functions, or a function with really huge sized or many local objects, reaches that stack-memory again.
It even can happen that you reach the same program part again, and overwrite your old local function variable with the new function variable. All this is very dangerous and should be heavily discouraged.
Do not use pointers to local objects!
A good thing to remember are these simple rules, and they apply to both parameters and return types...
Value - makes a copy of the item in question.
Pointer - refers to the address of the item in question.
Reference - is literally the item in question.
There is a time and place for each, so make sure you get to know them. Local variables, as you've shown here, are just that, limited to the time they are locally alive in the function scope. In your example having a return type of int* and returning &i would have been equally incorrect. You would be better off in that case doing this...
void func1(int& oValue)
{
oValue = 1;
}
Doing so would directly change the value of your passed in parameter. Whereas this code...
void func1(int oValue)
{
oValue = 1;
}
would not. It would just change the value of oValue local to the function call. The reason for this is because you'd actually be changing just a "local" copy of oValue, and not oValue itself.