Segmentation fault at the end of destructor - c++

I don't know if this question is going to be clear, since I can't give too many details (I'm using a TPL and wrote a huge amount of lines myself). But I'll give it a try.
I am experiencing a segmentation fault which I can't understand. There is a structure (which I didn't design but should be well tested) whose destructor looks like this
Data::~Data()
{
if(A_ != 0) {
delete A_;
A_ = 0;
}
if(B_ != 0) {
delete B_;
B_ = 0;
}
if(C_ != 0) {
delete C_;
C_ = 0;
}
} // HERE
What's bothering me is that, while debugging, I get that the segfault happens at the line marked with 'HERE'. The class Data has only A_, B_ and C_ as dynamically allocated attributes. I also tried to explicitly call the destructor on the other non-dynamic composite attributes, to see if something went wrong during their destruction, but again the segfault happens at the end of the destructor. What kind of errors can give a segfault at that point?.
I hope the question is clear enough, I will add details if needed.
Edit: thanks for the replies. I know it's a scarse piece of code, but the whole library is of course too big (it comes from Trilinos, by the way, but I think the error is not their fault, it must be my mistake in handling their structures. I used short names to keep the problem more compact). Some remarks that somebody asked in the comment replies:
about the checks before the delete(s) and the raw pointers: as I said, it's not my choice. I guess it's a double protection in case something goes wrong and A_, B_ or C_ has been already deleted by some other owner of the data structure. The choice raw-pointers vs shared_ptr or other safe/smart pointers is probably due to the fact that this class is almost never used directly but only by an object of class Map that has a pointer to Data. This class Map is implemented in the same library, so they probably chose raw pointers since they knew what they were handling and how.
yes, the data structure is shared by all the copies of the same object. In particular, there is a Map class that contains a pointer to a Data object. All the Map's that are copies of one each other, share the same Data. A reference counter keeps track of how many Map's are holding a pointer to the data. The last Map to be destroyed, deletes the data.
the reference counter of the Data structure works correctly, I checked it.
I am not calling the destructor of this class. It is called automatically by the destructor of an object of class Map that has a pointer to Data as attribute.
Data inherits from BaseData, whose (virtual) destructor doesn't do anything, since it's just an interface defining class.
It's hard to post the code that reproduce the problem. For many reasons. The error appears only with more than 2 processes (it's an mpi program), and my guess it that a process has some list that is empty and tries to access some element.
about the error details. I can give you here the last items in the backtrace of the error during debugging (I apologize for the bad format, but I don't know how to put it nicely):
0x00007ffff432fba5 in raise (sig=) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
0x00007ffff43336b0 in abort () at abort.c:92
0x00007ffff436965b in __libc_message (do_abort=, fmt=) at ../sysdeps/unix/sysv/linux/libc_fatal.c:189
0x00007ffff43736d6 in malloc_printerr (action=3, str=0x7ffff4447780 "free(): corrupted unsorted chunks", ptr=) at malloc.c:6283
0x00007ffff4379ea3 in __libc_free (mem=) at malloc.c:3738
0x0000000000c21f71 in Epetra_BlockMapData::~Epetra_BlockMapData ( this=0x1461690, __in_chrg=) at /home/bartgol/LifeV/trilinos/trilinos-10.6.4-src/packages/epetra/src/Epetra_BlockMapData.cpp:110
To conclude, let me restate my doubt: what kind of errors can appear AT THE END of the destructor, even if ALL the attributes have been deleted already? Thanks again!

One problem that can cause a segfault at a function exit is heap or stack corruption.
It is possible that some other part of your program is causing problems. Something like double-destruction, or buffer overrun can cause memory corruption.
Often, debug builds of programs will include a check at function exit to ensure that the stack is intact. If it's not, well, you see the results.

When the explicit body of the class destructor completes, it proceeds to perform some implicit actions: it calls base class and member destructors (in case you have base classes and members with non-trivial destructors) and, if necessary, it calls raw memory deallocation function operator delete (yes, in a typical implementation operator delete is actually called from inside the destructor). One of these two implicit processes caused the crash in your case, apparently. There's no way to say precisely without more information.
P.S. Stylistically the code is awful. Why are they checking for null before doing delete? What is the point of nulling deleted pointers in the destructor?

It's hard to tell from the scarce code you show. It could be easily that you already released resources one of your class members or your base class uses in it's own destructor.

Related

Reading the virtual function table (vtable) pointer?

Is there a well-defined way of accessing the vtable of a class? When debugging in visual studio I can expand 'this' like: this->_ptr->__vfptr. But this path does not seem to be available from code.
I need this for a unit test of a custom heap implementation (embedded environment).
Background
We had a bug where an object being allocated on our custom heap (which isn't anything more than an array of a certain size) was working as expected until we wanted to add an object having a virtual function (it took quite some time before we realized that this addition was the cause of the problem). The mistake that we did was to assign an object to memory where no object had been initialized prior to assignment. We did not pay much attention when writing that code and as it worked with everything else and was tested, we considered it working. Here's some sample code:
int array_ptr[sizeof(SomeObject)];
*((SomeObject*) array_ptr) = SomeObject(); // Does only partially initialize the object!
Once we realized this line was the issue, it also became clear why that was the case.
Aha, I get it now, with the clarification from the comments.
You're calling CFoo::operator= on raw memory that only has the size of a CFoo. That's indeed not going to set a vtable, on common implementations. This is specific to how assignment in C++ works. Object assignment in C++ is defined to be slicing. If you assign a Derived object to a Base class, you're calling Base::operator=(Base const& src). This only copies the Base sub-object of the Derived object.
The reason why C++ chose this model is because that means the Base object doesn't change size when you assign a Derived value to it, at the obvious price of losing the extra information.
The net effect is that C++ objects do not change type after construction. Practically, that means the type, and the vtable can be fixed by the constructor. The assignment operator won't touch it.
So, by calling the assignment operator on raw memory, you get Undefined Behavior, in particular an uninitialized (garbage) vtable. You can't count on it being all zeroes. Also, in more complicated cases with multiple and virtual inheritance, there are additional data fields to find the various sub-objects. Those would be uninitialized as well. Note that these additional data fields may contain absolute pointers. memcpy such an object, and you'd point back to subobjects of the original.
Can you detect this? No. All your attempts to access the memory are Undefined Behavior, by virtue of there not being a CFoo object in the raw memory.
The solution is placement new. This is the magical incantation that turns raw memory into an object. It can use any constructor, including move constructors and copy constructors, but (barring exceptions) will leave you with a valid object, with proper polymorphic behavior.
Ok, so learning from MSalters and other commenters above I understand there is no straight forward way of reading the vtable pointer. However, I came up with a solution that was enough for my needs (i.e. to test that the vtable pointer is properly initialized). So here's the code (note that I assume that what I get is the vtable pointer as sizeof(size_t) == sizeof(EmptyClassWithOneVirtualFunction)):
class EmptyClassWithOneVirtualFunction
{
virtual void testFunction() {}
};
void test_staticNew_object_vtable()
{
EmptyClassWithOneVirtualFunction correctObject;
EmptyClassWithOneVirtualFunction* object = mem::static_new<EmptyClassWithOneVirtualFunction>();
size_t* correctObjectVtablePtr = ( (size_t*) &correctObject );
size_t* objectVtablePtr = ( (size_t*) object );
TS_ASSERT_EQUALS( *objectVtablePtr, *correctObjectVtablePtr );
}
It should be pointed out that this is test code that is built in debug mode without optimization. To be able to catch this error even in this not entirely "safe" way is more valuable to me than to skip doing it just because there is no right way to do it.

Should I reset primitive member variable in destructor?

Please see following code,
class MyClass
{
public:
int i;
MyClass()
{
i = 10;
}
};
MyClass* pObj = nullptr;
int main()
{
{
MyClass obj;
pObj = &obj;
}
while (1)
{
cout << pObj->i; //pObj is dangling pointer, still no crash.
Sleep(1000);
}
return 0;
}
obj will die once it comes out of scope. But I tested in VS 2017, I see no crash even after I use it.
Is it good practice to reset int member varialbe i?
Accessing a member after an object got destroyed is undefined behavior. It may seem like a good to set members in a destructor to a predictable and most likely unexpected value, e.g., a rather large value or a value with specific bit pattern making it easy to recognize the value in a debugger.
However, this idea is flawed and dwarved by the system:
All classes would need to play along and instead of concentrating on creating correct code developers would spent time (both development time as well as run-time) making pointless change.
Compilers happen get rather smart and can detect that changes in destructor are not needed. Since a correct program cannot detect whether the change was made they may not make the change at all. This effect is an actual issue for security applications where, e.g., a password should be erased from memory so it cannot be read (using some non-portable mean).
Even if the value gets set to a specific value, memory gets reused and the values get overwritten. Especially with objects on the stack it is most likely that the memory is used for something else before you see the bad value in a debugger.
Even when resetting values you would necessarily see a "crash": a crash is caused by something being setup to protect against something invalid. In your example you are accessing an int on the stack: the stack will remain accessible from a CPU point of view and at best you'd get an unexpected value. Use of unusual pointer values typically leads to a crash because the memory management system tries to access a location which isn't mapped but even that isn't guaranteed: on a busy 32 bit system pretty much all memory may be in use. That is, trying to rely on undefined behavior being detect is also futile.
Correspondingly, it is much better to use good coding practices which avoid dangling references right away and concentrate on using these. For example, I'm always initializing members in the member initializer list, even in the rare cases they end up getting changed in the body of the constructor (i.e., you'd write your constructor as MyClass(): i() {}).
As a debugging tool it may be reasonable to replace the allocation functions (ideally the allocator object but potentially the global operator new()/operator delete() and family with a version which doesn't quickly hand out released memory and instead fills the released memory with a predictable pattern. Since these actions slow down the program you'd only use this code in a debug build but it is relatively simple to implement once and easy to enable/disable centrally it may be worth the effort. In practice I don't think even such a system pays off as use of managed pointers and proper design of ownership and lifetime avoid most errors due to dangling references.
The behaviour of code you gave is undefined. Partial case of undefined behaviour is working as expected, so here is nothing strange that the code works. Code can work now and it can broke anyway at any time depending of compiler version, compiler options, stack content and a moon phase.
So first and most important is to avoid dangling pointers (and all other kinds of undefined behaviour) everywhere.
What about clearing variables in destructor, I found a best practice:
Follow coding rules saving me from mistakes of access to unallocated or destroyed objects. I cannot describe it in a few words but rules are pretty common (see here and anywhere).
Analyze code by humans (code review) or by statical analyzers (like cppcheck or PVS-Studio or another) to avoid cases similar to one you described above.
Do not call delete manually, better use scoped_ptr or similar object lifetime managers. When delete is reasonable, I usually (usually) set pointer to nullptr after deletion to keep myself from mistakes.
Use pointers as rare as it possible. References are preferred.
When objects of my class used outside and I suspect that somebody can access it after deletion I can put signature field inside, set it to something like 0xDEAD in destructor and check at enter or every public method. Here be careful to not slow down your code to unacceptable speed.
After all of this setting i from your example to 0 or -1 is redundant. As for me it's not a thing you should focus your attention.

C++ Destructor crashing on a call to delete

I have a very weird and probably obvious problem, but I can't seem to find the bug. I've got a class object that holds a pointer to another class object, and when the first's deconstructer is called, it tries to delete its pointer, but instead causes a segfault without ever entering the second's deconstructor.
Specifically, I have an instance of the class Optimizer:
class Optimizer {
public:
Optimizer();
~Optimizer();
//Lot's of public methods and such
private:
PredictionRenderer *_predictionRenderer;
//Lot's of member variables
};
Optimizer::~Optimizer() {
std::cout<<"optimizer destructor:"<<_predictionRenderer->getWidth()<<std::endl;
delete _predictionRenderer; //THIS LINE CRASHES AND NEVER MAKES IT INTO THE PREDICTION RENDERER DECONSTRUCTOR
//other calls
}
(This is a big project, so for brevity I removed all the extra methods/variables).
Optimizer has a pointer to a PredictionRenderer object, _predictionRenderer. This pointer is initialized during the call to the constructor. The pointer is private, and I checked and made sure that it can't "get out" (that is, no one outside this Optimizer object can get ahold of this pointer. It is never returned by any of optimizer's methods and it is never passed to any method by an optimizer method).
When attempting to delete the Optimizer object, my program segfaults on the delete _predictionRenderer line. Execution never makes it into the PredictionRenderer deconstructor. I added in the print statement before the delete call to verify that the pointer was not NULL or already deleted, and the call to PredictionRenderer's getWidth method returns successfully, which suggests that it must be a valid pointer (is it possible to call a method of a deleted object?). Also, the print statement is only printed out once, so I'm pretty sure that the Optimizer object isn't being copied and deleted twice. Finally, the deconstructor for PredictionRenderer is never called, not by delete or anywhere else.
I have not idea what could be causing this. Does anyone have any insight into what is going on?
Edit: As I mentioned in the comments, this code base is big. I apologize for not showing much, but I can't really show everything as there just isn't enough space. This is someone else's code that I'm using, and from what I can tell, he never actually destructs this object, he just lets it get deallocated when the program quits. I could do this too, but it seems like a hack and not a good way to do business.
Are you sure there is even a _predictionRenderer to delete? You should check first.
if (_predictionRenderer)
delete _predictionRenderer;
If you try to delete a pointer that was never allocated memory, your program will crash.
nothing wrong in the lines of code you posted.
i suggest cross-check the value of _predictionRenderer ptr right after its initialization and compare it with the value you see in the Optimizer::~Optimizer(). they should be the same, if not you have a problem outside. may be your container object is corrupted.

Repeated destructor calls and tracking handles in C++/CLI

I'm playing around with C++/CLI, using the MSDN documentation and the ECMA standard, and Visual C++ Express 2010. What struck me was the following departure from C++:
For ref classes, both the finalizer and destructor must be written so they can be executed multiple times and on objects that have not been fully constructed.
I concocted a little example:
#include <iostream>
ref struct Foo
{
Foo() { std::wcout << L"Foo()\n"; }
~Foo() { std::wcout << L"~Foo()\n"; this->!Foo(); }
!Foo() { std::wcout << L"!Foo()\n"; }
};
int main()
{
Foo ^ r;
{
Foo x;
r = %x;
} // #1
delete r; // #2
}
At the end of the block at #1, the automatic variable xdies, and the destructor is called (which in turn calls the finalizer explicitly, as is the usual idiom). This is all fine and well. But then I delete the object again through the reference r! The output is this:
Foo()
~Foo()
!Foo()
~Foo()
!Foo()
Questions:
Is it undefined behavior, or is it entirely acceptable, to call delete r on line #2?
If we remove line #2, does it matter that r is still a tracking handle for an object that (in the sense of C++) no longer exists? Is it a "dangling handle"? Does its reference counting entail that there will be an attempted double deletion?
I know that there isn't an actual double deletion, as the output becomes this:
Foo()
~Foo()
!Foo()
However, I'm not sure whether that's a happy accident or guaranteed to be well-defined behaviour.
Under which other circumstances can the destructor of a managed object be called more than once?
Would it be OK to insert x.~Foo(); immediately before or after r = %x;?
In other words, do managed objects "live forever" and can have both their destructors and their finalizers called over and over again?
In response to #Hans's demand for a non-trivial class, you may also consider this version (with destructor and finalizer made to conform to the multiple-call requirement):
ref struct Foo
{
Foo()
: p(new int[10])
, a(gcnew cli::array<int>(10))
{
std::wcout << L"Foo()\n";
}
~Foo()
{
delete a;
a = nullptr;
std::wcout << L"~Foo()\n";
this->!Foo();
}
!Foo()
{
delete [] p;
p = nullptr;
std::wcout << L"!Foo()\n";
}
private:
int * p;
cli::array<int> ^ a;
};
I'll just try to address the issues you bring up in order:
For ref classes, both the finalizer and destructor must be written so they can be executed multiple times and on objects that have not been fully constructed.
The destructor ~Foo() simply auto-generates two methods, an implementation of the IDisposable::Dispose() method as well as a protected Foo::Dispose(bool) method which implements the disposable pattern. These are plain methods and therefore may be invoked multiple times. It is permitted in C++/CLI to call the finalizer directly, this->!Foo() and is commonly done, just like you did. The garbage collector only ever calls the finalizer once, it keeps track internally whether or not that was done. Given that calling the finalizer directly is permitted and that calling Dispose() multiple times is allowed, it is thus possible to run the finalizer code more than once. This is specific to C++/CLI, other managed languages don't allow it. You can easily prevent it, a nullptr check usually gets the job done.
Is it undefined behavior, or is it entirely acceptable, to call delete r on line #2?
It is not UB and entirely acceptable. The delete operator simply calls the IDisposable::Dispose() method and thus runs your destructor. What you do inside it, very typically calling the destructor of an unmanaged class, may well invoke UB.
If we remove line #2, does it matter that r is still a tracking handle
No. Invoking the destructor is entirely optional without a good way to enforce it. Nothing goes wrong, the finalizer ultimately will always run. In the given example that will happen when the CLR runs the finalizer thread one last time before shutting down. The only side effect is that the program runs "heavy", holding on to resources longer than necessary.
Under which other circumstances can the destructor of a managed object be called more than once?
It's pretty common, an overzealous C# programmer may well call your Dispose() method more than once. Classes that provide both a Close and a Dispose method are pretty common in the framework. There are some patterns where it is nearly unavoidable, the case where another class assumes ownership of an object. The standard example is this bit of C# code:
using (var fs = new FileStream(...))
using (var sw = new StreamWriter(fs)) {
// Write file...
}
The StreamWriter object will take ownership of its base stream and call its Dispose() method at the last curly brace. The using statement on FileStream object calls Dispose() a second time. Writing this code so that this doesn't happen and still provide exception guarantees is too difficult. Specifying that Dispose() may be called more than once solves the problem.
Would it be OK to insert x.~Foo(); immediately before or after r = %x;?
It's okay. The outcome is unlikely to be pleasant, a NullReferenceException would be the most likely result. This is something that you should test for, raise an ObjectDisposedException to give the programmer a better diagnostic. All standard .NET framework classes do so.
In other words, do managed objects "live forever"
No, the garbage collector declares the object dead, and collects it, when it cannot find any references to the object anymore. This is a fail-safe way to memory management, there is no way to accidentally reference a deleted object. Because doing so requires a reference, one that the GC will always see. Common memory management problems like circular references are not an issue either.
Code snippet
Deleting the a object is unnecessary and has no effect. You only delete objects that implement IDisposable, an array does not do so. The common rule is that a .NET class only implements IDisposable when it manages resources other than memory. Or if it has a field of a class type that itself implements IDisposable.
It is furthermore questionable whether you should implement a destructor in this case. Your example class is holding on to a rather modest unmanaged resource. By implementing the destructor, you impose the burden on the client code to use it. It strongly depends on the class usage how easy it is for the client programmer to do so, it definitely is not if the object is expected to live for a long time, beyond the body of a method so that the using statement isn't usable. You can let the garbage collector know about memory consumption that it cannot track, call GC::AddMemoryPressure(). Which also takes care of the case where the client programmer simply doesn't use Dispose() because it is too hard.
Guidelines from standard C++ still apply:
Calling delete on an automatic variable, or one that's already been cleaned up, is still a bad idea.
It's a tracking pointer to a disposed object. Dereferencing such is a bad idea. With garbage collection, the memory is kept around as long as any non-weak reference exists, so you can't access the wrong object by accident, but you still can't use this disposed object in any useful way, since its invariants probably no longer hold.
Multiple destruction can only happen on managed objects when your code is written in really bad style that would have been UB in standard C++ (see 1 above and 4 below).
Explicitly calling the destructor on an automatic variable, then not creating a new one in its place for the automatic destruction call to find, is still a bad idea.
In general, you think think of object lifetime as separate from memory allocation (just like standard C++ does). Garbage collection is used to manage deallocation -- so the memory is still there -- but the object is dead. Unlike standard C++, you can't go and reuse that memory for raw byte storage, because parts of the .NET runtime may assume the metadata is still valid.
Neither the garbage collector nor "stack semantics" (automatic variable syntax) use reference counting.
(Ugly details: disposing an object doesn't break the .NET runtime's own invariants concerning that object, so you can probably even still use it as a threading monitor. But that just makes an ugly hard-to-understand design, so please don't.)

new object causes corruption on the heap

I've been struggling with a heap corruption problem for a few days. I was first warned by the vs 2005 debugger that I may have corrupted the heap, after deleting an object I had previously new'ed. Doing research on this problem led me to gflags and the page heap setting. After enabling this setting for my particular image, it supposedly pointed me to the line that is actually causing the corruption.
Gflags identified the constructor for the object in question as the culprit. The object derives as follows:
class POPUPS_EXPORT MLUNumber : public MLUBase
{
...
}
class POPUPS_EXPORT MLUBase : public BusinessLogicUnit
{
...
}
I can instantiate an MLUNumber in a separate thread, and no heap corruption occurs.
I can instantiate a different class, that also inherits from MLUBase, that does not cause heap corruption.
The access violation raises due to the corruption occurs on the opening brace of the constructor, which appears to be because of the implicit initializing of the object (?).
The base class constructor (MLUBase) successfully finishes.
From digging with the memory window in vs 2005, it appears that there was not enough space allocated for the actual object. My guess is that enough was allocated for the base class only.
The line causing the fault:
BusinessLogicUnit* biz = new MLUNumber();
I'm hoping for either a reason that might cause this, or another troubleshooting step to follow.
Unfortunately, with the information given, it's not possible to definitively diagnose the problem.
Some things you may want to check:
Make sure BusinessLogicUnit has a virtual destructor. When deleteing objects through a base pointer, a virtual destructor must be present in the base class for the subclass to be properly destructed.
Make sure you're building all source files with the same preprocessor flags and compiler options. A difference in flags (perhaps between debug/release flags?) could result in a change in structure size, and thus an inconsistency between sizes reported in different source files.
It's possible for some types of heap corruption to go undetected, even with your gflags settings. Audit your other heap uses to try to find the source of your issues as well. Ideally you should put together a minimal test case that will reliably crash, but with a minimum amount of activity, so you can narrow down the cause.
Try a clean solution and rebuild; I've occasionally seen timestamps getting screwed up, and an old object file can get in with an out-of-date structure definition. Worth checking at least :)
BusinessLogicUnit* biz = new MLUNumber();
How do you delete the memory? Using the base-class pointer? Have you made the destructor of BusinessLogicUnit virtual? It must be virtual.
class BusinessLogicUnit
{
public:
//..
virtual ~BusinessLogicUnit(); //it must be virtual!
};
Otherwise deleting the derived class object through the base-class pointer invokes undefined behavior as per the C++ Standard.
BusinessLogicUnit is not an MLUNumber. Why would you allocate this way? Instead
BusinessLogicUnit* biz = new BusinessLogicUnit();
Or maybe you do something like this?
struct A
{
SomeType & m_param;
A(SomeType & param) : m_param(param)
{
...use m_param here...
}
};
A a(SomeType()); // passing a temporary by reference
Then that's undefined behaviour, because the referenced temporary dies right after m_param(param) happens..
I agree with bdonlan that there isn't enough information yet to figure out what's wrong. There are a lot of good suggestions here, but just guessing possible reasons why an application is crashing is not a smart way to root cause an issue.
You've done the right thing by enabling instrumentation (pageheap) to help you narrow down the problem. I would continue down this path by finding out exactly which memory address is causing the access violation (and where the address came from).