Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Curious case of segfault

I faced a weird case of segfault in a c++ program. I'm able to reproduce it in a small code, but don't understand why is it happening. Here is the code:

a.hpp:

#pragma once
#include <boost/shared_ptr.hpp>
#include "b.hpp"

class A
{
    public:
        explicit A ();    
    private:
        std::string str1_;
        B b_;
        std::string str2_;
};

typedef boost::shared_ptr< A > A_ptr;

a.cpp

#include "a.hpp"
A::A () {}

b.hpp

#pragma once
#include <string>

class B
{   
    public:
        B ();
    private:
        std::string str1_;
};   

b.cpp

#include "b.hpp"    
B::B () {}

main.cpp

#include "a.hpp"

int main ()
{
    A_ptr a( new A() );
}

Output of make:

% make
g++ -Wall -Wextra -g -fno-inline -O0   -c -o main.o main.cpp
g++ -Wall -Wextra -g -fno-inline -O0   -c -o a.o a.cpp
g++ -Wall -Wextra -g -fno-inline -O0   -c -o b.o b.cpp
g++  -o main main.o a.o b.o 
dsymutil main

Now this runs fine. I remove B b_ (declaration of b_) from a.hpp, save a.cpp (to trigger a build) and run make again:

% make
g++ -Wall -Wextra -g -fno-inline -O0   -c -o a.o a.cpp
g++  -o main main.o a.o b.o 
dsymutil main

And now program segfaults with:

(gdb) bt
#0  0x00007fff97f106e5 in std::string::_Rep::_M_dispose ()
#1  0x00007fff97f10740 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string ()
#2  0x0000000100001091 in A::~A (this=0x1001008b0) at a.hpp:8
#3  0x00000001000011da in boost::checked_delete<A> (x=0x1001008b0) at checked_delete.hpp:34
#4  0x0000000100001026 in boost::detail::sp_counted_impl_p<A>::dispose (this=0x1001008d0) at sp_counted_impl.hpp:78
#5  0x0000000100000d9a in boost::detail::sp_counted_base::release (this=0x1001008d0) at sp_counted_base_gcc_x86.hpp:145
#6  0x0000000100000dd4 in boost::detail::shared_count::~shared_count (this=0x7fff5fbff568) at shared_count.hpp:305
#7  0x0000000100000f2b in boost::shared_ptr<A>::~shared_ptr (this=0x7fff5fbff560) at shared_ptr.hpp:159
#8  0x0000000100000aac in main () at main.cpp:5

And if I make clean and make, then program runs without segfault. Please help me understand why program segfaults if a member from class is removed and project is built without clean.

like image 419
Vikas Avatar asked Oct 17 '12 21:10

Vikas


People also ask

What is causing segfault?

A segmentation fault (aka segfault) is a common condition that causes programs to crash; they are often associated with a file named core . Segfaults are caused by a program trying to read or write an illegal memory location.

How do you resolve a segfault?

It can be resolved by having a base condition to return from the recursive function. A pointer must point to valid memory before accessing it.

Can you recover from a segfault?

On both Windows and Linux, the segfault handler function is passed a "context struct", which includes the state of the registers at the failure site. Ostensibly, this is so people can repair the problem that caused the segfault (it also lets you do nifty things like userspace segment handling).

Is a segfault an exception?

They are both called exceptions, but they originate at different levels of the software/hardware of the system. Technically, you can catch segfaults with a signal handler for SIGSEGV . However, as Ivaylo explains, it's is not, typically, allowed to just "try again" if you get a segfault.


1 Answers

On your second run of make:

% make
g++ -Wall -Wextra -g -fno-inline -O0   -c -o a.o a.cpp
g++  -o main main.o a.o b.o 
dsymutil main

you are recompiling just a.cpp. Then linking to the rest of object files produced in the previous run of make. This will make main.cpp use the older definition of class A (contained in a.h), while the new object file for class A (a.o) will use the newer definition, hence the crash.

(Concretely, new class A has different size, so the memory it needs to be reserved on the stack in main() is different and the disposition of its member variables is also different).

This is clearly a problem of faulty dependencies in your Makefile.

When you run make clean/make, all the files will use the same, correct definition for class A and everything will work out correctly.

like image 104
sergio Avatar answered Oct 23 '22 01:10

sergio