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.
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.
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.
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).
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With