2012-10-17 2 views
5

J'ai fait face à un cas étrange de segfault dans un programme C++. Je suis capable de le reproduire dans un petit code, mais je ne comprends pas pourquoi cela se passe. Voici le code:Curieux cas de segfault

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()); 
} 

Sortie de faire:

% 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 

Maintenant, cela fonctionne très bien. Je supprimer B b_ (déclaration de b_) de a.hpp, enregistrez a.cpp (pour déclencher une accumulation) et exécutez make nouveau:

% 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 

Et maintenant segfaults programme avec:

(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 

Et si je make clean et make , alors le programme s'exécute sans segfault. S'il vous plaît aidez-moi à comprendre pourquoi programmer des erreurs de segmentation si un membre de la classe est supprimé et que le projet est construit sans nettoyage.

Répondre

10

Sur votre deuxième série de 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 

vous compilez juste a.cpp. Puis lier au reste des fichiers objet produits dans l'exécution précédente de make. Cela fera main.cpp utiliser l'ancienne définition de class A (contenue dans a.h), tandis que le nouveau fichier objet pour class A (a.o) utilisera la définition la plus récente, d'où le plantage.

(Concrètement, le nouveau a une taille différente, donc la mémoire dont il a besoin d'être réservé sur la pile en main() est différente et la disposition de ses variables membres est également différente).

Ceci est clairement un problème de dépendances défectueuses dans votre Makefile. Lorsque vous exécutez make clean/make, tous les fichiers utiliseront la même définition correcte pour class A et tout fonctionnera correctement.