The question:
I have some code executing which is very unsafe. My question is, does this code trigger undefined behavior or is it 'correct' (= behavior fully defined).
Some context:
I have a program which has shown strange bugs/crashes in the past, which repeatedly also vanish again without reason.
I have identified some pieces of (pointer) logic as a potential source of these bugs. Still, the bugs can also be caused by other part of that code.
The bugs typically happen in Release builds, and not in Debug builds in case that matters.
I have taken these lines of (pointer) logic code and created a clear minimum-working example.
This minimum-working example runs without problems which I know is no conclusive proof that no undefined behavior is happening.
Therefore, I ask if someone sees if some 'C++ rules' are broken (= results in undefined behavior).
I build and develop this in Visual Studio 2019 and/or 2022.
I know this code contains very bad patterns. However, this is a minimal working example and in the actual code, many things are out of my control so I cannot simply change much of it.
For now, I just want to learn if certain pointer operations result in defined or undefined behavior.
In case one or more operation do trigger undefined behavior, I would be grateful if someone can point out which operations they are and why they trigger undefined behavior.
The code:
Main program, minimum_working_example.cpp:
#include <iostream>
#include <sstream>
#include "CppObject.h"
int main()
{
/* Create a shared pointer on the heap.
* The lifetime of this shared_ptr is managed by some managed C# code which wraps this C++ code.
* That is why the shared_ptr is created on the heap, so C# can manage the lifetime of the pointer and therefore the C++ object.
*/
std::shared_ptr<void>* regularPointerToSmartPointer = new std::shared_ptr<void>(); // Create a shared pointer on the heap, and store a regular pointer pointing to it.
// Create an CppObject and store it in the shared_ptr<void> (note that this should add a reference to the correct type deleter into the shared_ptr).
int someValue = 5; // Some value stored in the CppObject, just for illustration.
*regularPointerToSmartPointer = std::make_shared<CppObjectStuff::CppObject>(someValue); // Create an object on the heap, create a smart pointer pointing to it, and store this smart pointer on the heap at the memory reserved in the previous step.
// Just get the raw pointer to object.
void* regularPointerToObject = (*regularPointerToSmartPointer).get();
// Convert pointer to string.
std::stringstream ss1;
ss1 << std::hex << regularPointerToObject; // Pointer to hex string.
std::string regularPointerToObjectString = ss1.str();
/* Many other operations can happen here
* e.g. like passing this string to all sorts of objects which could
desire to use the instance of CppObject.
*/
// Convert string to back pointer.
std::stringstream ss2;
ss2 << regularPointerToObjectString;
intptr_t raw_ptr = 0;
ss2 >> std::hex >> raw_ptr; //Hex string to int.
void* regularPointerToObjectFromString = reinterpret_cast<void*>(raw_ptr);
// Convert the void pointer to a CppObject pointer.
CppObjectStuff::CppObject* pointerToCppObject = static_cast<CppObjectStuff::CppObject*>(regularPointerToObjectFromString);
// Do something with the CppObject behind the pointer.
int result = pointerToCppObject->GiveIntValue();
// Print result.
std::cout << "This code runs fine:" << "\n";
std::cout << result;
// Delete the shared_ptr which in turn deletes the CppObject (something the managed C# code would normally do).
delete regularPointerToSmartPointer;
}
For reference, CppObject.h:
namespace CppObjectStuff
{
class CppObject
{
public:
CppObject(int value) { _intValue = value; };
int GiveIntValue() { return _intValue; };
private:
int _intValue;
};
}
One item that could cause discussion:
I already researched specifically the following tricky case which I concluded should be allowed, see e.g. this bog post.
Note, this is similar but not fully identical to the usage in my code above so there could still be stuff I misunderstand:
// Start scope
{
// Create object in shared_ptr
std::shared_ptr<void> regularPointerToSmartPointer = std::make_shared<CppObjectStuff::CppObject>(someValue);
}
// Scope ended, shared_ptr went out of scope and should delete the `ppObjectStuff::CppObject` created before.
Related
I’m a C++ beginner with a background in Python, Java, and JS, so I’m still learning the ropes when it comes to pointers.
I have a vector of shared pointers. Inside of a different function, I assign a shared pointer to a variable and add it to the vector. If I try to access the added element after that function exits, a segmentation fault happens:
class Bar
{
private:
std::vector<std::shared_ptr<Foo>> fooVector;
}
void Bar::addToFoo()
{
std::shared_ptr<Foo> foo (new Foo(…));
fooVector.push_back(foo);
}
void Bar::otherMethod()
{
// this method gets called sometime after addToFoo gets called
…
fooVector[anIndex]->baz(); // segfaults
…
}
But, if push_back a shared pointer and not a variable, it works.
// this works:
fooVector.push_back(std::shared_ptr<Foo>(new Foo(…)));
// this segfaults:
std::shared_ptr<Foo> foo (new Foo(…));
fooVector.push_back(foo);
I believe it happens because the foo variable gets deleted when the addToFoo function exits (correct me if I’m wrong). How do you push_back a shared_ptr variable to a vector of shared_ptrs in C++?
Why Use A Variable
Though pushing shared_ptrs to vectors directly without variables works, I prefer to use variables in order to do this:
std::shared_ptr<Rider> rider;
switch (iProcessorModesParam)
{
case PEAKS_MODE:
rider = std::shared_ptr<Rider>(new PeaksRider(…));
break;
case RMS_MODE:
rider = std::shared_ptr<Rider>(new RMSrider(…));
break;
}
volumeRiders.push_back(rider);
PeaksRider and RMSrider are subclasses of Rider. I want to store all subtypes of Rider in the same vector of Riders. I learned that adding subtypes of Rider to a vector of Riders doesn’t work and pointers are needed in order to achieve this kind of polymorphism:
std::vector<Rider> // doesn’t work with subtypes
std::vector<*Rider>
std::vector<std::shared_ptr<Rider>>
Having the std::shared_ptr<Rider> rider; variable avoids repeating the .push_back(…) code for each type of Rider.
Instead of assigning shared pointer, user reset method.
rider.reset(new PeaksRider(…));
other that this, your code snippets seems to okay to me.
segfault may have caused because of the index variable ( which may be out of range). i suggest you to use .at(index) for accessing pointer from vector and wrap that part of code in a try..catch block and see what is the real error.
And regarding...
I believe it happens because the foo variable gets deleted when the addToFoo function exits (correct me if I’m wrong).
This is not true, share_ptrs use a local counter for #of references. as soon as you pushed the pointer to vector the counter gets incremented to 2 and event after control exits the function the counter is decremented to 1. so, your object is not destroyed yet.
There is no problem on creating a shared pointer instance, storing it in a variable, and doing a push_back to a vector after that. Your code should be fine as long as the index that you use when calling "otherMethod" is valid. However, I have a couple of suggestions for your code:
When you create a shared_ptr, it is highly recommended to do it through "std::make_shared" to ensure the safety and correctness of your code in all situations. In this other post you will find a great explanation: Difference in make_shared and normal shared_ptr in C++
When accessing positions of a vector using a variable that may contain values that would cause an out-of-bounds access (which usually leads to segmentation faults) it is a good practice to place asserts before using the vector, so you will detect these undesired situations.
I just wrote a small snippet that you can test to illustrate what I just mentioned:
#include <iostream>
#include <vector>
#include <memory>
#include <cassert>
class Foo
{
public:
int data = 0;
};
class Bar
{
public:
void addNewFoo(int d)
{
std::shared_ptr<Foo> foo(new Foo());
foo->data = d;
fooVector.push_back(foo);
}
void addNewFooImproved(int d)
{
auto foo = std::make_shared<Foo>();
foo->data = d;
fooVector.push_back(foo);
}
void printFoo(int idx)
{
assert(idx < fooVector.size());
std::cout << fooVector[idx]->data << std::endl;
}
private:
std::vector<std::shared_ptr<Foo>> fooVector;
};
int main()
{
Bar b;
b.addNewFoo(10);
b.addNewFoo(12);
b.addNewFooImproved(22);
b.printFoo(1);
b.printFoo(2);
b.printFoo(0);
}
I'm using a library that, in order to construct some object that I use, expects a raw pointer to an object. I'm not sure what it will do with the pointer, to make my code as safe as possible, what should I pass to this function?
Use a unique pointer - if they decide to delete the pointer, I will do a double-delete
Keep track of a raw pointer - bad because I have to remember to write delete, but it could still be a double-delete
Use auto duration and give them a pointer Give them a reference - their code will error if they call delete
Use a shared pointer - same double-delete problem as unique pointer, but now my scope won't hurt their pointer
Based on my reading, option 3 seems like what I should do - they shouldn't be calling delete on the pointer, and this format enforces that. But what if I don't know whether they now or in the future will call delete on the reference I gave them? Use a shared pointer and say "not my fault about the double delete"?
#include <memory>
#include <iostream>
class ComplexObj {
public:
ComplexObj() : m_field(0) {}
ComplexObj(int data) : m_field(data) {}
void print() { std::cout << m_field << std::endl; }
private:
int m_field;
};
class BlackBox {
public:
BlackBox(ComplexObj* data) {
m_field = *data;
// Do other things I guess...
delete data;
std::cout << "Construction complete" << std::endl;
}
void print_data() { m_field.print(); }
private:
ComplexObj m_field;
};
int main(int argc, char* argv[]) {
// Use a smart pointer
std::unique_ptr<ComplexObj> my_ptr(new ComplexObj(1));
BlackBox obj1 = BlackBox(my_ptr.get());
obj1.print_data();
my_ptr->print(); // Bad data, since BlackBox free'd
// double delete when my_ptr goes out of scope
// Manually manage the memory
ComplexObj* manual = new ComplexObj(2);
BlackBox obj2 = BlackBox(manual);
obj2.print_data();
manual->print(); // Bad data, since BlackBox free'd
delete manual; // Pair new and delete, but this is a double delete
// Edit: use auto-duration and give them a pointer
ComplexObj by_ref(3);
BlackBox obj3 = BlackBox(&by_ref); // they can't call delete on the pointer they have
obj3.print_data();
by_ref.print();
// Use a shared pointer
std::shared_ptr<ComplexObj> our_ptr(new ComplexObj(4));
BlackBox obj4 = BlackBox(our_ptr.get());
obj4.print_data();
our_ptr->print(); // Bad data, they have free'd
// double delete when our_ptr goes out of scope
return 0;
}
Other questions I read related to this topic...
unique_ptr.get() is legit at times
I should pass by reference
I think I am case 2 and should pass by reference
You cannot solve this problem with the information you have. All choices produce garbage.
You have to read the documentation of the API you are using.
Doing any of your 4 answers without knowing if they take ownership of the pointer will result problems.
Life sometimes sucks.
If you have a corrupt or hostile API, the only halfway safe thing to do is to interact with it in a separate process, carefully flush all communication, and shut down the process.
If the API isn't corrupt or hostile, you should be able to know if it is taking ownership of the pointed to object. Calling an API without knowing this is a common mistake in novice C++ programmers. Don't do it. Yes, this sucks.
If this API is at all internal and you have any control, seek to make all "owning pointer" arguments be std::unique_ptr<>s. That makes it clear in the API that you intend to own the object and delete it later.
Deleting the double pointer is will cause the harmful effect like crash the program and programmer should try to avoid this as its not allowed.
But sometime if anybody doing this then i how do we take care of this.
As delete in C++ is noexcept operator and it'll not throw any exceptions. And its written type is also void. so how do we catch this kind of exceptions.
Below is the code snippet
class myException: public std::runtime_error
{
public:
myException(std::string const& msg):
std::runtime_error(msg)
{
cout<<"inside class \n";
}
};
void main()
{
int* set = new int[100];
cout <<"memory allcated \n";
//use set[]
delete [] set;
cout <<"After delete first \n";
try{
delete [] set;
throw myException("Error while deleting data \n");
}
catch(std::exception &e)
{
cout<<"exception \n";
}
catch(...)
{
cout<<"generic catch \n";
}
cout <<"After delete second \n";
In this case i tried to catch the exception but no success.
Pleas provide your input how we'll take care of these type of scenario.
thanks in advance!!!
Given that the behaviour on a subsequent delete[] is undefined, there's nothing you can do, aside from writing
set = nullptr;
immediately after the first delete[]. This exploits the fact that a deletion of a nullptr is a no-op.
But really, that just encourages programmers to be sloppy.
Segmentation fault or bad memory access or bus errors cannot be caught by exception. Programmers need to manage their own memory correctly as you do not have garbage collection in C/C++.
But you are using C++, no ? Why not make use of RAII ?
Here is what you should strive to do:
Memory ownership - Explicitly via making use of std::unique_ptr or std::shared_ptr and family.
No explicit raw calls to new or delete. Make use of make_unique or make_shared or allocate_shared.
Make use of containers like std::vector or std::array instead of creating dynamic arrays or allocating array on stack resp.
Run your code via valgrind (Memcheck) to make sure there are no memory related issues in your code.
If you are using shared_ptr, you can use a weak_ptr to get access to the underlying pointer without incrementing the reference count. In this case, if the underlying pointer is already deleted, bad_weak_ptr exception gets thrown. This is the only scenario I know of when an exception will be thrown for you to catch when accessing a deleted pointer.
A code must undergo multiple level of testing iterations maybe with different sets of tools before committing.
There is a very important concept in c++ called RAII (Resource Acquisition Is Initialisation).
This concept encapsulates the idea that no object may exist unless it is fully serviceable and internally consistent, and that deleting the object will release any resources it was holding.
For this reason, when allocating memory we use smart pointers:
#include <memory>
#include <iostream>
#include <algorithm>
#include <iterator>
int main()
{
using namespace std;
// allocate an array into a smart pointer
auto set = std::make_unique<int[]>(100);
cout <<"memory allocated \n";
//use set[]
for (int i = 0 ; i < 100 ; ++i) {
set[i] = i * 2;
}
std::copy(&set[0], &set[100] , std::ostream_iterator<int>(cout, ", "));
cout << std::endl;
// delete the set
set.reset();
cout <<"After delete first \n";
// delete the set again
set.reset();
cout <<"After delete second \n";
// set also deleted here through RAII
}
I'm adding another answer here because previous answers focus very strongly on manually managing that memory, while the correct answer is to avoid having to deal with that in the first place.
void main() {
std::vector<int> set (100);
cout << "memory allocated\n";
//use set
}
This is it. This is enough. This gives you 100 integers to use as you like. They will be freed automatically when control flow leaves the function, whether through an exception, or a return, or by falling off the end of the function. There is no double delete; there isn't even a single delete, which is as it should be.
Also, I'm horrified to see suggestions in other answers for using signals to hide the effects of what is a broken program. If someone is enough of a beginner to not understand this rather basic stuff, PLEASE don't send them down that path.
I'm trying to write a linked queue in C++, but I'm failing so far. I've created 2 files by now: my main.cpp and box.h. When trying to use my box, I receive the following message:
Description Resource Path Location Type
conversion from ‘Box*’ to
non-scalar type ‘Box’
requested main.cpp /QueueApplication line
14 C/C++ Problem
My code is as follows:
box.h
#ifndef BOX_H_
#define BOX_H_
template<class T>
class Box
{
public:
Box(T value)
{
this->value = value;
this->nextBox = NULL;
}
T getValue()
{
return this->value;
}
void setNext(Box<T> next)
{
this->nextBox = next;
}
private:
T value;
Box<T> nextBox;
};
#endif /* BOX_H_ */
main.cpp
#include<iostream>
#include "box.h"
using namespace std;
int main(int argc, char** argv)
{
Box<int> newBox = new Box<int>();
cout << "lol";
cin.get();
cin.ignore();
return 0;
}
Could you guys help me?
PS: before someone ask me why not to use stl ... I'm in a data structures class.
Removing unimportant stuff, we see you've declared a new class like this:
template<class T>
class Box
{
T value;
Box<T> nextBox;
};
How big is Box<T>?
Clearly
sizeof Box<T> >= sizeof(Box<T>::value) + sizeof(Box<T>::nextBox)
sizeof Box<T> >= sizeof(T) + sizeof(Box<T>)
0 >= sizeof (T)
uh-oh
The problem is with this line
Box<int> newBox = new Box<int>();
The new operator returns a pointer to a Box object created on the heap. The pointer will be of type Box<int>*. The left side of that expression declares a Box object. You can't directly assign a pointer-to-X to an X. You should probably just omit the new keyword unless you have a reason to want to manage the storage lifetime of the object manually. Incidentally, I'm betting you come from Java, where new is always required to create objects. Not so in C++.
Also I think it's awesome that your data structures class is introducing you to templates right off the bat.
I believe your nextBox should be a pointer.
Box<T> * nextBox;
Method setNext should deal with pointers too.
void setNext(Box<T> * next)
And newBox should be a pointer.
Box<int> * newBox = new Box<int>();
Since you come from a Java background, you are assuming that all of your objects are references. Syntax is a little different in C++.
There are multiple problems here.
First of all, in order to implement a linked list (or a queue that uses a linked list) in C++ you need to use pointers. In Java everything is a reference. C++, on the other hand, makes a clear distinction between objects and pointers to objects. (There are also references to objects, but they are irrelevant here).
Let's also forget the templates for a moment, because they are not part of the problem here.
class Box
{
int value;
Box nextBox; // wrong! should be a pointer
};
is wrong, because nextBox must be a pointer to the next element of the list/queue. The correct
way would be Box *nextBox;
By the same token setNext() should also take a pointer to Box as its argument. setNext(Box b) is an example of pass-by-value, i. e. this member function (method in Java lingo) gets its own copy of the entire Box object. This could lead to performance issues if the object is large, not to mention that any changes done to it by the function will be invisible to the caller. What you want instead here is pass-by-reference, which is accomplished by using a pointer.
The final point is that new in C++ always returns a pointer. You should have Box<int> *newBox = new Box<int>;
When you use new, you get a pointer to an object, not a plain object. Declare your variable as a pointer or just allocate your object on the stack instead.
I hope this makes sense to you, since if it doesn't, you should probably go back and read more about the basics of OOP in C++.
Guys. No raw pointers in C++ unless you really need them. Please. Especially for some poor soul who doesn't even know that operator new returns a pointer. Get a std::auto_ptr or a std::shared_ptr.
Hi can someone tell why in Linux and windows the same problem occurs :
#include <iostream>
using namespace std;
class A
{
private:
int _dmember;
public:
void func()
{
cout<<"Inside A!! "<<endl;
cout<<_dmember; // crash when reach here.
}
};
int main ()
{
A* a= NULL;
a->func(); // prints "Inside A!!!"
return 1;
}
can someone tell why this weird behivior occurs ? i mean ,
the a->func() was not supposed to get inside the func() ,...?
this is unwated behavior ,
why the above behivor occurs?
EDIT: Of course , a* =null was intentionaly!! so for all who answered "this is undefined behavior" or "you should never try to call a function on a NULL pointer !!", come on.... that was the point. and this behavior was explained correctly by some of you.
This is undefined behaviour. You must never call functions on a null pointer.
With that out of the way, let's answer the question I think you're asking: why do we get partway into the function anyway?
When you are invoking UB, the compiler is free to do anything, so it's allowed to emit code that works anyway. That's what happens on some (many?) systems in this particular case.
The reason that you're able to call the function on a null pointer successfully is that your compilers don't store the function "in" the object. Rather, the above code is interpreted somewhat like this:
class A {
int _dmember;
};
void A::func(A *this) {
cout << "Inside A!!" << endl;
cout << this->_dmember << endl;
}
int main() {
A *a = ...;
A::func(a);
}
So, you see there is nothing that actually prevents you from calling a function on a null pointer; it'll just invoke the body of the function, with the this pointer set to null. But as soon as the function tries to dereference the this pointer by accessing a field inside the class, the operating system steps in and kills your program for illegal memory access (called segmentation fault on Linux, access violation on Windows).
Nitpicker's corner: Virtual functions are a different story.
Undefined behavior because you are accessing a NULL pointer:
A* a= NULL;
a->func(); // is not defined by the language
Note that even if func() didn't try to access a member variable, the behavior still is undefined. For example, the following code could run without errors, but it is not correct:
func()
{
cout<<"Inside A!! "<<endl;
}
EDIT: With my full respect, C++ doesn't suck!
What you need is a smart pointer, not a raw pointer. As my professor says always, if you don't know what you are doing in C/C++, it is better not to do it!
Use boost::scoped_ptr, and enjoy exception safety, automatic memory management, zero overhead and NULL checking:
struct test
{
int var;
void fun()
{
std::cout << var;
}
};
int main()
{
boost::scoped_ptr<test> p(NULL);
p->fun(); // Assertion will fail, Happy debugging :)
}
Dereferencing a null pointer is undefined behaviour.
Everything could happen, so don't do it.
You must check that the pointer is valid before dereferencig it. this pointer cannot be null so you wouldn't avoid the undefined behaviour.
Most compilers just pass the pointer to the class as the first parameter (The this pointer). If you don't go on to de-reference the this pointer then you are not actually going to cause a crash. Your this pointer, inside the functiom, will simply be NULL.
As AraK pointed out this is undefined behaviour so your mileage mat vary...
Aren't you supposed to allocate a memory for your pointer? I just wonder what is the intention to call a function of a NULL pointer? It's supposed to crash immediately. It doesn't crash on the line where you don't call to A member _dmember,but the moment you call it your function crashes cause the object is simply not allocated. _dmember points on undefined memory... That's why it crashes
Its a null pointer, you simply can't define what should happen if we call a function on it.
Any pointer variable is supposed to point to some object.
Your declaration A * a = NULL;
does not point anywhere and so will not yield the results as it should.
You can however try this
A * a = NULL;
A b;
a=&b;
a->func();
this will yield the output.
Since there are no virtual functions in your class, it's easier here to think about what C code would be generated to represent this type. Approximately:
#include <stdio.h>
typedef struct
{
int d_;
} A;
FILE* print_a_to(A* a, FILE* dest)
{
return fprintf(dest, "Inside A!! \n") < 0 ||
fprintf(dest, "%d", a->d_) < 0 ?
NULL :
dest;
}
int main(int argc, char* argv[])
{
A* a = NULL;
return NULL == print_a_to(a, stdout) ?
-1 :
0;
}
Look at the second line of function print_a_to; see the dereferencing of pointer a? Per the first line of function main, you're passing NULL as the value of pointer a. Dereferencing a null pointer here is equivalent to calling a member function on your class that needs access to its member variables through a null pointer.
if i was'nt clear,
i am not trying to do deliberately below:
A* a=NULL;
a->f();
i wrote that code just to check why is it working , and ofcourse i was disappointed and my reason to be disapointed is that i debug very big program in Redhat-Linux , through log-files concept( meaning - Printing Entering,Exiting from functions to logs, including printing imporant values).
AND, on my way on the logs i hoped that if im on specific STACK of function calls i hoped at least the instances operating these functions are alive, but as i discovered and disapointed its not ought to be , which for me disapointement because it makes the debug through log files even more difficult.
I hope you described the symptoms exactly as what you saw. I tried on both Windows and Linux. Linux gives a segment fault, and Windows displays the error dialog.
The address area around 0x0 is protected by Windows and Linux. Reading and writing in this memory area will cause the OS throws an exception. Your application can catch the exception. Most application do not, and OS default handling routine is to print some error message and terminate the program.
One may ask why the message ""Inside A!! " is printed before termination. The answer is that at backend, C++ compiler converts class methods into procedure calls. This step does not involve pointer dereference. You can think that the result look like this:
void A_func(A* a)
{
cout<<"Inside A!! "<<endl;
cout<<a->_dmember; // crash when reach here.
}
A* a = NULL;
A_func(a);
The dereference of NULL pointer happened at the second statement. So the first statement was executed just fine.
the point is that the -> operator on class object (with no vtable) is not a dereference of the pointer
a->foo()
is really shorthand for
A::foo(a)
where the first param gets transformed into the this pointer. Its when u try to deref 'this' by referring to member variable that things go bad.