Unexpected runtime error (segmentation fault) - c++

I am currently optimizing a memory intensive application to occupy lesser memory. What I am trying to do in the following code is to allocate the file stream objects ifstream and ofstream dynamically in order to free them exactly after it's use is no longer needed. The code functions perfectly for allocation/de-allocation of ofstream but crashes at runtime due to a possible segmentation fault when the memory contents of ifstream is de-allocated. The following is a snippet of the original code:
#include <fstream>
using namespace std;
// Dummy class to emulate the issue at hand
class dummy {
private:
int randINT;
static bool isSeeded;
public:
dummy() { randINT=rand(); }
int getVal() { return randINT; }
};
bool dummy::isSeeded=false;
int main(int argc, const char* argv[]) {
// Binary file I/O starts here
dummy * obj;
ofstream * outputFile;
ifstream * inputFile;
outputFile=new ofstream("bFile.bin",ios::binary);
if (!(*outputFile).fail()) {
obj=new dummy;
cout << "Value to be stored: " << (*obj).getVal() << "\n";
(*outputFile).write((char *) obj, sizeof(*obj)); // Save object to file
(*outputFile).close();
delete obj;
// don't assign NULL to obj; obj MUST retain the address of the previous object it pointed to
} else {
cout << "Error in opening bFile.bin for writing data.\n";
exit(1);
}
delete outputFile; // This line throws no errors!
inputFile=new ifstream("bFile.bin",ios::binary);
if (!(*inputFile).fail()) {
(*inputFile).read((char *) obj,sizeof(dummy)); // Read the object of type 'dummy' from the binary file and allocate the object at the address pointed by 'obj' i.e. the address of the previously de-allocated object of type 'dummy'
cout << "Stored Value: " << (*obj).getVal() << "\n";
(*inputFile).close();
} else {
cout << "Error in opening bFile.bin for reading data.\n";
exit(1);
}
delete inputFile; // Runtime error is thrown here for no reason!
cout << "\n-----END OF PROGRAM-----\n";
}
The above code saves an object to a binary file when the user evokes save functions. As stated in the code above, the de-allocation of inputFile pointer throws a runtime error.
Please note that I am using clang(more specifically, clang++) to compile the project.
Thanks in advance.

std::basic_istream::read(char_type*address, streamsize count) reads up to count characters and places them at address. It does not create any objects at address, as you seem to believe. The address must point to a valid chunk of memory at least count*sizeof(char_type) in size. By passing the address of a deleted object, you violate that condition: your code is broken and segmentation fault is not unexpected.
EDIT
What you're doing is undefined behaviour, short UB. When you do that, nothing is guaranteed and any logic about what happens in which order invalid. The program is allowed to do anything, including immediately crashing, running for a while and then crashing, or "make demons fly out of your nose".
In your case, I suspect that std::basic_istream::read() writing to unprotected memory causes some data to be overwritten, for example the address of another object, which later causes the segmentation fault. But this is pure speculation and not really worth pursuing.
In your case no object is created. The binary file just contains some bytes. The read() copies them to the address provided, which was not reserved for that purpose. To avoid the UB, simply add
obj = new dummy;
before the read to create an object.
If you want to re-use the memory from the previous object, you could use placement new (see points 9 and 10 of that link). For example
char*buffer = nullptr; // pointer to potential memory buffer
if(writing) {
if(!buffer)
buffer = new char[sizeof(dummy)]; // reserve memory buffer
auto pobj = new(buffer) dummy(args); // create object in buffer
write(buffer,sizeof(dummy)); // write bytes of object
pobj->~pobj(); // destruct object, but don't free buffer
}
if(reading) {
if(!buffer)
buffer = new char[sizeof(dummy)]; // not required if writing earlier
read(buffer,sizeof(dummy)); // read bytes into object
auto pobj = reinterpret_case<dummy*>(buffer); // no guarantees here
use(pobj); // do something with the object read
pobj->~pobj(); // destruct object
}
delete[] buffer; // free reserved memory
Note that if the reading does not generate a valid object, the later usage of that object, i.e. the call to its destructor, may crash.
However, all this micro-optimisation is pointless anyway (it's only worth doing if you can avoid many calls to new and delete). Don't waste your time with that.

Related

Accessing pointers after deletion [duplicate]

This question already has answers here:
What happens to the pointer itself after delete? [duplicate]
(3 answers)
Closed 3 years ago.
I have a code snippet like below. I have created some Dynamic memory allocation for my Something class and then deleted them.
The code print wrong data which I expect but why ->show does not crash?
In what case/how ->show will cause crash?
Is it possible to overwrite the same memory location of i, ii, iii with some other object?
I am trying to understand why after delete which frees up the memory location to be written with something else still have information about ->show!
#include <iostream>
#include <vector>
class Something
{
public:
Something(int i) : i(i)
{
std::cout << "+" << i << std::endl;
}
~Something()
{
std::cout << "~" << i << std::endl;
}
void show()
{
std::cout << i << std::endl;
}
private:
int i;
};
int main()
{
std::vector<Something *> somethings;
Something *i = new Something(1);
Something *ii = new Something(2);
Something *iii = new Something(3);
somethings.push_back(i);
somethings.push_back(ii);
somethings.push_back(iii);
delete i;
delete ii;
delete iii;
std::vector<Something *>::iterator n;
for(n = somethings.begin(); n != somethings.end(); ++n)
{
(*n)->show(); // In what case this line would crash?
}
return 0;
}
The code print wrong data which I expect but why ->show does not crash?
Why do you simultaneously expect the data to be wrong, but also that it would crash?
The behaviour of indirecting through an invalid pointer is undefined. It is not reasonable to expect the data to be correct, nor to expect the data to be wrong, nor to expect that it should crash, nor to expect that it shouldn't crash - in particular.
In what case/how ->show will cause crash?
There is no situation where the C++ language specifies the program to crash. Crashing is a detail of the particular implementation of C++.
For example, a Linux system will typically force the process to crash due to "segmentation fault" if you attempt to write into a memory area that is marked read-only, or attempt to access an unmapped area of memory.
There is no direct way in standard C++ to create memory mappings: The language implementation takes care of mapping the memory for objects that you create.
Here is an example of a program that demonstrably crashes on a particular system:
int main() {
int* i = nullptr;
*i = 42;
}
But C++ does not guarantee that it crashes.
Is it possible to overwrite the same memory location of i, ii, iii with some other object?
The behaviour is undefined. Anything is possible as far as the language is concerned.
Remember, a pointer stores an integer memory address. On a call to delete, the dynamic memory will be deallocated but the pointer will still store the memory address. If we nulled the pointer, then program would crash.
See this question: What happens to the pointer itself after delete?

Creating a message queue using boost interprocess - memory access violation

I am creating a message queue which is used by two processes. One of them is putting something in it and the other is reading it.
The message queue is following struct I created.
struct MSGQueue {
Action actions_[256];
int count;
MSGQueue() { count = 0; }
interprocess_mutex mutex;
Action Pop() {
--count;
return actions_[count];
}
void Put(Action act) {
actions_[count] = act;
++count;
}
};
Action is a custom class I created.
class Action {
public:
// Getter functions for the member
private:
std::string name_;
ActionFn action_fn_; // this is an enum
void* additional_data_;
}
I am creating a shared memory like this in the main program
shm_messages = shared_memory_object(create_only,"MySharedMemory", read_write);
shm_messages.truncate(sizeof(MSGQueue));
region = mapped_region(shm_messages_, read_write);
In my other program I am opening it and put an action in the queues array of actions.
boost::interprocess::shared_memory_object shm_messages_;
boost::interprocess::mapped_region region_;
shm_messages_ = shared_memory_object(open_only, "MySharedMemory", read_write);
shm_messages_.truncate(sizeof(MSGQueue));
region_ = mapped_region(shm_messages_, read_write);
//Get the address of the mapped region
void * addr = region_.get_address();
//Construct the shared structure in memory
MSGQueue * data = static_cast<MSGQueue*>(addr);
Action open_roof("OpenRoof", ActionFn::AFN_ON, NULL);
{ // Code block for scoped_lock. Mutex will automatically unlock after block.
// even if an exception occurs
scoped_lock<interprocess_mutex> lock(data->mutex);
// Put the action in the shared memory object
data->Put(open_roof);
}
The main program is checking if we got some new messages and if there is one it shall read it and put it in a list.
std::vector<ghpi::Action> actions;
//Get the address of the mapped region
void * addr = region_.get_address();
//Construct the shared structure in memory
MSGQueue * data = static_cast<ghpi::Operator::MSGQueue*>(addr);
if (!data) {
std::cout << " Error while reading shared memory" << std::endl;
return actions;
}
{
scoped_lock<interprocess_mutex> lock(data->mutex);
while (data->count > 0) {
actions.push_back(data->Pop()); // memory access violation here
std::cout << " Read action from shm" << std::endl;
}
}
The second program which is putting the action works fine. But after it run the main program is seeing the count has increased and is trying to read and throws an memory access violation at me.
I don't know why i am getting this violation error. Is there something special about sharing class objects or structs?
Let's take a look at the objects you're trying to pass between processes:
class Action {
// ...
std::string name_;
}
Well, looky here. What do we have here? We have here a std::string.
Did you know that sizeof(x), where x is a std::string will always give you the same answer, whether the string is empty, or has their entire contents of "War And Peace"? That's because your std::string does a lot of work that you don't really have to think about. It takes care of allocating the requirement memory for the string, and deallocating when it is no longer used. When a std::string gets copied or moved, the class takes care of handling these details correctly. It does its own memory allocation and deallocation. You can think of your std::string to consist of something like this:
namespace std {
class string {
char *data;
size_t length;
// More stuff
};
}
Usually there's a little bit more to this, in your typical garden-variety std::string, but this gives you the basic idea of what's going on.
Now try to think of what happens when you put your std::string into shared memory. Where do you think that char pointer still points to? Of course, it still points to somewhere, someplace, in your process's memory where your std::string allocated the memory for whatever string it represents. You have no idea where, because all that information is hidden in the string.
So, you placed this std::string in your shared memory region. You did place the std::string itself but, of course, not the actual string that it contains. There's no way you can possibly do this, because you have no means of accessing std::string's internal pointers and data. So, you've done that, and you're now trying to access this std::string from some other process.
This is not going to end well.
Your only realistic option is to replace the std::string with a plain char array, and then go through the extra work of making sure that it's initialized properly, doesn't overflow, etc...
Generally, in the context of IPC, shared memory, etc..., using any kind of a non-trivial class is a non-starter.

How to delete the array of structures if the memory block was manually overwritten

I know that example provided below is a rather bad pattern to follow, but I would like to ask this question out of curiosity.
In this situation:
int main (int argc, char **argv) {
struct MyStruct {
virtual ~MyStruct() = default;
int dummyField;
};
int numpack = 1000;
int memoryBlockSize = numpack*sizeof(MyStruct);
char* buf = new char[memoryBlockSize];
memset(buf, 0, memoryBlockSize);
{
MyStruct packets[numpack];
memcpy(&packets, buf, memoryBlockSize);
} // segmentation fault on scope exit
MyStruct* packets = new MyStruct[numpack];
memcpy(packets, buf, memoryBlockSize);
delete[] packets; // segmentation fault on delete attempt
delete[] buf;
return 0;
}
segmentation fault is expected, because upon packets destruction it is not possible to find the destructor in the MyStruct's virtual table (memory was overwritten with zeros). In such a case, is it possible to gracefully delete the memory block pointed by packets?
Maybe there is a possibility to provide the (pointer + block size) to the delete function?
Or maybe I can try to repair the block pointed by packets by copying a memory from another memory block allocated in the same way (but the pointers in the virtual table will point to a different places in the memory):
MyStruct* anotherPackets = new MyStruct[numpack];
memcpy(packets, anotherPackets, memoryBlockSize);
It depends on MyStruct. If it has a non trivial destructor, because for example it contains a non empty std::string object, you have lost because when you erase the object, you will create a memory leak with the string characters. Things could even be worse depending on subobjects.
But is all you need is that destructors can be successfully called when packets go out of scope, you can simply use a placement new to construct (new) objects inside the array:
{
MyStruct packets[numpack];
memcpy(&packets, buf, memoryBlockSize);
for (int i=0; i<numpack; i++) {
new(packets+i) MyStruct(); // re-creates an object
}
} // the new objects are being destructed here
But as the destructors have not been called on initial objects, anything can happen because of that (that's what Undefined Behaviour means...). So please never do that in real code.

How to copy a non null terminated string to dynamic memory

First off, this is not a duplicate. My question is how to do it with dynamic memory. The reason this is distinct is because my delete[] is hanging.
So, here's what I have:
class PacketStrRet {
public:
PacketStrRet(char p_data[], int p_len) : len(p_len) {
data = new char[p_len];
memcpy(data, p_data, p_len * sizeof(char));
}
~PacketStrRet() {
delete[] data;
data = nullptr;
}
char* data;
int len;
};
And yes, I'm aware that my code is not using the best practices. I'll clean it up later.
The problem I'm having is in the DTOR. That delete is hanging forever. The data being passed in to the CTOR is not dynamic memory, so I need to make it dynamic so things don't go out of scope. p_len holds the correct amount of data, so there's no problem there.
From what I've read, memcpy seems to be the most likely culprit here. So how do I copy a string that is not null-terminated to dynamic memory, and then still be able to delete it later?
Thanks.
The problem is not the delete, only everything that comes before and even that would be ok if there didn't occur any problems.
class PacketStrRet {
// Use RAII
std::unique_ptr<char> data; // I own this data and will destroy it.
// now the parent class is also only movable, use shared_ptr if you can't live with that.
int len;
public:
PacketStrRet(
// <RED ALERT>
char p_data[], int p_len // user can lie to us.
// </RED ALERT>
) try : // function try block, se 1)
len(p_len), data(new char[p_len]) {
memcpy(data, p_data.get(), p_len * sizeof(char));
} catch(const std::exception& e) {
std::cerr << "arg=" << arg << " failed: " << e.what() << '\n';
}
~PacketStrRet() {
// unique_ptr takes care of memory management and garbage collection.
}
// access functions
};
Now the possible errors you could make to blow the code up.
You could have copied the object, essentially making two owning raw pointers to the same data. This would blow up at delete, you coudl use memory-sanitizer / valgrind to confirm this happens. Use smart pointers to save you the trouble, the unique pointer should cause a compiler error if you tried to copy, unless you memcpy the entire structure ignoring the copy/assignment constructors.
You could give the wrong len to the constructor, what is the source of the data and len? Valgrind / memory-sanitizer can save you.
The memory corruption could happen in a totally different place. Valgrind / memory-sanitizer can save you.
In case valgrind mem-san are too much, you can try to make a check for double delete, if you make a counter in c'tor and d'tor and if it ever goes to negative you have your error.
In this class your at least missing a copy constructor. Check up on rule of 3, 5, 7 and 0 (zero) to find out how many you need.
1) http://en.cppreference.com/w/cpp/language/function-try-block
Try to use std:: copy(). It will be like this:
std::copy(p_data, p_data + p_len, data).

Program Crashes on NULL Pointer object

I am trying a code which Goes like this:-
class test{
int test_int;
public:
virtual int show()
{
return test_int;
}
void set_int(int data){
std::cout<<"received data "<< data <<endl;
test_int = data;
}
};
int main()
{
test *ptr=new test();
ptr=NULL;
ptr->set_int(5);
return 0;
}
Now the problem i am facing is my program after printing the data which i am sending through set_int function got printed but the program crashes just after the completition of the function(set_int).
Am i doing any mistake that is not according to the language standards?
TIA.
Am i doing any mistake that is not according to the language standards?
Yes, you are.
You may not call member functions on a pointer that does not point to a valid object of that type. A null pointer never points to a valid object.
The trivial fix here is to remove the line ptr=NULL;. That way ptr still points to an object when the member function is invoked. This also allows you to fix the memory leak by deleting the pointer later. As a sidenote: avoid manual memory management.
You have pointer to test (test*) set to dynamicaly allocated memory representing instance of that class.
Right after that, you wrote "Nah, I do not need it anymore" and you forget where that newly allocated memory was.
Finally, you are trying to access an object on address 0, which is an invalid operation and will cause runtime error.
You probably meant to do this
int main()
{
test *ptr = new test();
ptr->set_int(5);
// ptr = NULL; // wont free the memory allocated by new
delete ptr; // memory deallocation
ptr = NULL; // now we can safely forget that address (which is now invalid anyways)
return 0;
}