关于std::string出现在_M_dispose发生SIGABRT错误的问题

本文深入分析了一种特殊的程序错误,当GCC编译器在使用STL字符串时,在特定条件下会导致内存释放错误。错误源于不正确的结构体对齐设置,导致内存地址计算错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注意:这不是gcc/stl的bug。

例子程序如下:

inc.h

#include <stdio.h>

#pragma pack(1)

typedef struct {
    char    a1;
    char    a2;
    char    a3;
    char    a4;
} record_t;

main.cc

#include "inc.h"
#include <string>

/*
 * A test program to evaluate the miss use of pragma pack
 * leading to std::string's strange SEGV problem.
 */
int main(int argc, char** argv)
{
    std::string filename("abc.txt");
    std::string::size_type pos = filename.rfind('.');
    std::string prefix = filename.substr(0, pos);
    printf("prefix=%s\n", prefix.c_str());

    return 0;
}


Makefile

CXXFLAGS=-g -O2

all: testpack

.PHONY: all clean

%.o: %.cc
    $(CXX) $(CXXFLAGS) -c -o $@ $<

testpack: main.o
    $(CXX) -o testpack -O2 main.o

clean:
    rm testpack main.o -rf


在linux环境下,gcc3.3.3以上版本,编译运行,会出现以下错误:

prefix=abc
*** glibc detected *** /home/aaa/testpack/testpack: free(): invalid pointer: 0x0000000000601044 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3b7a87247f]
/lib64/libc.so.6(cfree+0x4b)[0x3b7a8728db]
/home/aaa/testpack/testpack(__gxx_personality_v0+0x1c5)[0x4008cd]
/lib64/libc.so.6(__libc_start_main+0xf4)[0x3b7a81d994]
/home/aaa/testpack/testpack(__gxx_personality_v0+0x71)[0x400779]

... (下略)


不加-O2参数,该错误不出现。


重新运行,调试过程:

(gdb) r
Starting program: /home/aaa/testpack/testpack
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x2aaaaaaab000
prefix=abc
*** glibc detected *** /home/aaa/testpack/testpack: free(): invalid pointer: 0x0000000000601044 ***

(gdb) f 7
#7  main (argc=<optimized out>, argv=<optimized out>) at main.cc:15

(gdb) p prefix
$1 = {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
    _M_p = 0x601058 "abc"}}


(释放prefix的_M_dataplus指向的区域时出现问题。看一下代码:)

(gdb) f 6
#6  ~basic_string (this=<optimized out>, __in_chrg=<optimized out>) at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/basic_string.h:478
478           { _M_rep()->_M_dispose(this->get_allocator()); }

(看一下_M_rep()的实现:)

(gdb) list 281
276
277           _CharT*
278           _M_data(_CharT* __p)
279           { return (_M_dataplus._M_p = __p); }
280
281           _Rep*
282           _M_rep() const
283           { return &((reinterpret_cast<_Rep*> (_M_data()))[-1]); }
284
285           // For the internal use we have functions similar to `begin'/`end'

(看一下_M_data()的实现:)

(gdb) list 273
268
269         private:
270           // Data Members (private):
271           mutable _Alloc_hider      _M_dataplus;
272
273           _CharT*
274           _M_data() const
275           { return  _M_dataplus._M_p; }
276

(获取的_Rep*指针应为_M_dataplus._M_p减去一个_Rep结构体大小。看一下_Rep结构体大小:)

(gdb) p sizeof(std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep)
$4 = 20

(看一下这个结构体的详细信息:)

(gdb) ptype std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep
type = struct std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep
        : public std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep_base {
    static const size_t _S_max_size;
    static const char _S_terminal;
    static size_t _S_empty_rep_storage[3];
  public:
    static std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep & _S_empty_rep(void);
    bool _M_is_leaked(void) const;
    bool _M_is_shared(void) const;
    void _M_set_leaked(void);
    void _M_set_sharable(void);
    void _M_set_length_and_sharable(unsigned long);
    char * _M_refdata(void);
    char * _M_grab(const std::allocator<char> &, const std::allocator<char> &);
    static std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep * _S_create(unsigned long, unsigned long, const std::allocator<char> &);
    void _M_dispose(const std::allocator<char> &);
    void _M_destroy(const std::allocator<char> &);
    char * _M_refcopy(void);
    char * _M_clone(const std::allocator<char> &, unsigned long);
}
(继承的部份应该没有占空间,看一下基类:)

(gdb) ptype std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep_base
type = struct std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep_base {
    size_t _M_length;
    size_t _M_capacity;
    _Atomic_word _M_refcount;
}

(因为是64位系统,所以前面两个size_t加起来是16位,后面一个_Atomic_word,经过在/usr/include下面grep,发现定义为int型,那么在当前x86_64的ABI下仍为4字节,加起来20字节……等一下!考虑对齐的话,最后一个int应该也占8字节,所以加起来应该是24字节,不是吗?为什么gdb显示20字节?)

(我们来检查一下倒底-24还是-20是这个真正的结构体:)
(gdb) p *(std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep_base*)(0x601058-20)
$9 = {_M_length = 12884901888, _M_capacity = 0, _M_refcount = -1}
(gdb) p *(std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep_base*)(0x601058-24)
$10 = {_M_length = 3, _M_capacity = 3, _M_refcount = 0}

(很显然我们的prefix存放的"abc"应该是后者。等一下,结尾的'\0'没有占空间?这个应该是分配的时候多分配了1个字节。capacity应该是没有包含terminating zero的。)

因此,该错误的直接原因在于,本程序的std::string在释放时,通过字符串位置计算字符串头部数据(一个共享的string data区域)时,把头部数据的大小搞错了。

再次注意:这肯定不是std::string的bug。你可以看到,inc.h里面有一句#pragma pack(1),这是相当糟糕的写法。没有#pragma pack(push, 1)和#pragma pop(),造成main.cc在引用时首先包含了这句#pragma pack,然后再引用stl的string头文件。那么在string头文件里面编译进目标文件的代码,会认为sizeof(_Rep_base)是20,而没有包含这个inc.h的代码(libc.so.6)会认为它是24。而stl的实现部份由内联函数直接在exe中展开,部份由libc.so.6预先提供,所以就会造成malloc/free计算出的地址不配对的问题。

关于stl的string为什么要用一块共享的string data实现,可以自行参考相关文档。

最后再次强调一下,这不是gcc的bug,也不是stl的bug,是人为灾害。


本文的目的在于,如果你遇到类似的错误而找不到原因时,可以参考检查。(当然,另外一个更可能的原因是你使用了包含多个gcc版本的动态库,你应当首先排除这个原因)

另外你或许可以从本文中学到一些调试技巧。


[完]



--- stderr: pilz_industrial_motion_planner /usr/bin/ld: CMakeFiles/unittest_pilz_industrial_motion_planner_direct.dir/src/unittest_pilz_industrial_motion_planner_direct.cpp.o: warning: relocation against `_ZTIN30pilz_industrial_motion_planner21PlanningContextLoaderE' in read-only section `.text._ZN12class_loader4impl19getAvailableClassesIN30pilz_industrial_motion_planner21PlanningContextLoaderEEESt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISA_EEPKNS_11ClassLoaderE[_ZN12class_loader4impl19getAvailableClassesIN30pilz_industrial_motion_planner21PlanningContextLoaderEEESt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISA_EEPKNS_11ClassLoaderE]' /usr/bin/ld: CMakeFiles/unittest_pilz_industrial_motion_planner_direct.dir/src/unittest_pilz_industrial_motion_planner_direct.cpp.o: in function `CommandPlannerTestDirect_FailOnLoadContext_Test::TestBody()::TestPlanningContextLoader::~TestPlanningContextLoader()': unittest_pilz_industrial_motion_planner_direct.cpp:(.text+0x93): undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::~PlanningContextLoader()' /usr/bin/ld: CMakeFiles/unittest_pilz_industrial_motion_planner_direct.dir/src/unittest_pilz_industrial_motion_planner_direct.cpp.o: in function `CommandPlannerTestDirect_FailOnLoadContext_Test::TestBody()': unittest_pilz_industrial_motion_planner_direct.cpp:(.text+0x3149): undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::PlanningContextLoader()' /usr/bin/ld: CMakeFiles/unittest_pilz_industrial_motion_planner_direct.dir/src/unittest_pilz_industrial_motion_planner_direct.cpp.o: in function `CommandPlannerTestDirect_FailOnLoadContext_Test::TestBody()::TestPlanningContextLoader::~TestPlanningContextLoader()': unittest_pilz_industrial_motion_planner_direct.cpp:(.text+0x4f): undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::~PlanningContextLoader()' /usr/bin/ld: CMakeFiles/unittest_pilz_industrial_motion_planner_direct.dir/src/unittest_pilz_industrial_motion_planner_direct.cpp.o: in function `std::_Sp_counted_ptr_inplace<CommandPlannerTestDirect_FailOnLoadContext_Test::TestBody()::TestPlanningContextLoader, std::allocator<CommandPlannerTestDirect_FailOnLoadContext_Test::TestBody()::TestPlanningContextLoader>, (__gnu_cxx::_Lock_policy)2>::_M_dispose()': unittest_pilz_industrial_motion_planner_direct.cpp:(.text+0x73): undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::~PlanningContextLoader()' /usr/bin/ld: CMakeFiles/unittest_pilz_industrial_motion_planner_direct.dir/src/unittest_pilz_industrial_motion_planner_direct.cpp.o: in function `std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > class_loader::impl::getAvailableClasses<pilz_industrial_motion_planner::PlanningContextLoader>(class_loader::ClassLoader const*)': unittest_pilz_industrial_motion_planner_direct.cpp:(.text._ZN12class_loader4impl19getAvailableClassesIN30pilz_industrial_motion_planner21PlanningContextLoaderEEESt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISA_EEPKNS_11ClassLoaderE[_ZN12class_loader4impl19getAvailableClassesIN30pilz_industrial_motion_planner21PlanningContextLoaderEEESt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISA_EEPKNS_11ClassLoaderE]+0x43): undefined reference to `typeinfo for pilz_industrial_motion_planner::PlanningContextLoader' /usr/bin/ld: CMakeFiles/unittest_pilz_industrial_motion_planner_direct.dir/src/unittest_pilz_industrial_motion_planner_direct.cpp.o:(.data.rel.ro+0x10): undefined reference to `typeinfo for pilz_industrial_motion_planner::PlanningContextLoader' /usr/bin/ld: CMakeFiles/unittest_pilz_industrial_motion_planner_direct.dir/src/unittest_pilz_industrial_motion_planner_direct.cpp.o:(.data.rel.ro+0x58): undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setModel(std::shared_ptr<moveit::core::RobotModel const> const&)' /usr/bin/ld: CMakeFiles/unittest_pilz_industrial_motion_planner_direct.dir/src/unittest_pilz_industrial_motion_planner_direct.cpp.o:(.data.rel.ro+0x60): undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setLimits(pilz_industrial_motion_planner::LimitsContainer const&)' /usr/bin/ld: ../../libplanning_context_loader_ptp.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::getAlgorithm[abi:cxx11]() const' /usr/bin/ld: warning: creating DT_TEXTREL in a PIE collect2: error: ld returned 1 exit status gmake[2]: *** [test/unit_tests/CMakeFiles/unittest_pilz_industrial_motion_planner_direct.dir/build.make:363:test/unit_tests/unittest_pilz_industrial_motion_planner_direct] 错误 1 gmake[1]: *** [CMakeFiles/Makefile2:553:test/unit_tests/CMakeFiles/unittest_pilz_industrial_motion_planner_direct.dir/all] 错误 2 gmake[1]: *** 正在等待未完成的任务.... /usr/bin/ld: CMakeFiles/unittest_pilz_industrial_motion_planner.dir/src/unittest_pilz_industrial_motion_planner.cpp.o: warning: relocation against `_ZTIN30pilz_industrial_motion_planner21PlanningContextLoaderE' in read-only section `.text._ZN12class_loader4impl19getAvailableClassesIN30pilz_industrial_motion_planner21PlanningContextLoaderEEESt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISA_EEPKNS_11ClassLoaderE[_ZN12class_loader4impl19getAvailableClassesIN30pilz_industrial_motion_planner21PlanningContextLoaderEEESt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISA_EEPKNS_11ClassLoaderE]' /usr/bin/ld: CMakeFiles/unittest_pilz_industrial_motion_planner.dir/src/unittest_pilz_industrial_motion_planner.cpp.o: in function `std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > class_loader::impl::getAvailableClasses<pilz_industrial_motion_planner::PlanningContextLoader>(class_loader::ClassLoader const*)': unittest_pilz_industrial_motion_planner.cpp:(.text._ZN12class_loader4impl19getAvailableClassesIN30pilz_industrial_motion_planner21PlanningContextLoaderEEESt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISA_EEPKNS_11ClassLoaderE[_ZN12class_loader4impl19getAvailableClassesIN30pilz_industrial_motion_planner21PlanningContextLoaderEEESt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISA_EEPKNS_11ClassLoaderE]+0x45): undefined reference to `typeinfo for pilz_industrial_motion_planner::PlanningContextLoader' /usr/bin/ld: warning: creating DT_TEXTREL in a PIE collect2: error: ld returned 1 exit status gmake[2]: *** [test/unit_tests/CMakeFiles/unittest_pilz_industrial_motion_planner.dir/build.make:361:test/unit_tests/unittest_pilz_industrial_motion_planner] 错误 1 gmake[1]: *** [CMakeFiles/Makefile2:835:test/unit_tests/CMakeFiles/unittest_pilz_industrial_motion_planner.dir/all] 错误 2 /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::getAlgorithm[abi:cxx11]() const' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `typeinfo for pilz_industrial_motion_planner::PlanningContextLoader' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setModel(std::shared_ptr<moveit::core::RobotModel const> const&)' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::PlanningContextLoader()' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::~PlanningContextLoader()' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setLimits(pilz_industrial_motion_planner::LimitsContainer const&)' collect2: error: ld returned 1 exit status gmake[2]: *** [test/unit_tests/CMakeFiles/unittest_trajectory_generator_lin.dir/build.make:364:test/unit_tests/unittest_trajectory_generator_lin] 错误 1 gmake[1]: *** [CMakeFiles/Makefile2:773:test/unit_tests/CMakeFiles/unittest_trajectory_generator_lin.dir/all] 错误 2 /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::getAlgorithm[abi:cxx11]() const' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `typeinfo for pilz_industrial_motion_planner::PlanningContextLoader' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setModel(std::shared_ptr<moveit::core::RobotModel const> const&)' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::PlanningContextLoader()' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::~PlanningContextLoader()' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setLimits(pilz_industrial_motion_planner::LimitsContainer const&)' collect2: error: ld returned 1 exit status gmake[2]: *** [test/unit_tests/CMakeFiles/unittest_trajectory_blender_transition_window.dir/build.make:380:test/unit_tests/unittest_trajectory_blender_transition_window] 错误 1 gmake[1]: *** [CMakeFiles/Makefile2:675:test/unit_tests/CMakeFiles/unittest_trajectory_blender_transition_window.dir/all] 错误 2 /usr/bin/ld: ../../libplanning_context_loader_ptp.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::getAlgorithm[abi:cxx11]() const' /usr/bin/ld: ../../libplanning_context_loader_ptp.so: undefined reference to `typeinfo for pilz_industrial_motion_planner::PlanningContextLoader' /usr/bin/ld: ../../libplanning_context_loader_ptp.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setModel(std::shared_ptr<moveit::core::RobotModel const> const&)' /usr/bin/ld: ../../libplanning_context_loader_ptp.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::PlanningContextLoader()' /usr/bin/ld: ../../libplanning_context_loader_ptp.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::~PlanningContextLoader()' /usr/bin/ld: ../../libplanning_context_loader_ptp.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setLimits(pilz_industrial_motion_planner::LimitsContainer const&)' collect2: error: ld returned 1 exit status gmake[2]: *** [test/unit_tests/CMakeFiles/unittest_trajectory_generator_ptp.dir/build.make:363:test/unit_tests/unittest_trajectory_generator_ptp] 错误 1 gmake[1]: *** [CMakeFiles/Makefile2:805:test/unit_tests/CMakeFiles/unittest_trajectory_generator_ptp.dir/all] 错误 2 /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::getAlgorithm[abi:cxx11]() const' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `typeinfo for pilz_industrial_motion_planner::PlanningContextLoader' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setModel(std::shared_ptr<moveit::core::RobotModel const> const&)' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::PlanningContextLoader()' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::~PlanningContextLoader()' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setLimits(pilz_industrial_motion_planner::LimitsContainer const&)' collect2: error: ld returned 1 exit status gmake[2]: *** [test/unit_tests/CMakeFiles/unittest_planning_context.dir/build.make:366:test/unit_tests/unittest_planning_context] 错误 1 gmake[1]: *** [CMakeFiles/Makefile2:1042:test/unit_tests/CMakeFiles/unittest_planning_context.dir/all] 错误 2 /usr/bin/ld: ../../libplanning_context_loader_circ.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::getAlgorithm[abi:cxx11]() const' /usr/bin/ld: ../../libplanning_context_loader_circ.so: undefined reference to `typeinfo for pilz_industrial_motion_planner::PlanningContextLoader' /usr/bin/ld: ../../libplanning_context_loader_circ.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setModel(std::shared_ptr<moveit::core::RobotModel const> const&)' /usr/bin/ld: ../../libplanning_context_loader_circ.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::PlanningContextLoader()' /usr/bin/ld: ../../libplanning_context_loader_circ.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::~PlanningContextLoader()' /usr/bin/ld: ../../libplanning_context_loader_circ.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setLimits(pilz_industrial_motion_planner::LimitsContainer const&)' collect2: error: ld returned 1 exit status gmake[2]: *** [test/unit_tests/CMakeFiles/unittest_trajectory_generator_circ.dir/build.make:364:test/unit_tests/unittest_trajectory_generator_circ] 错误 1 gmake[1]: *** [CMakeFiles/Makefile2:741:test/unit_tests/CMakeFiles/unittest_trajectory_generator_circ.dir/all] 错误 2 /usr/bin/ld: CMakeFiles/unittest_planning_context_loaders.dir/src/unittest_planning_context_loaders.cpp.o: warning: relocation against `_ZTIN30pilz_industrial_motion_planner21PlanningContextLoaderE' in read-only section `.text._ZN12class_loader4impl14createInstanceIN30pilz_industrial_motion_planner21PlanningContextLoaderEEEPT_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPNS_11ClassLoaderE[_ZN12class_loader4impl14createInstanceIN30pilz_industrial_motion_planner21PlanningContextLoaderEEEPT_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPNS_11ClassLoaderE]' /usr/bin/ld: CMakeFiles/unittest_planning_context_loaders.dir/src/unittest_planning_context_loaders.cpp.o: in function `std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > class_loader::impl::getAvailableClasses<pilz_industrial_motion_planner::PlanningContextLoader>(class_loader::ClassLoader const*)': unittest_planning_context_loaders.cpp:(.text._ZN12class_loader4impl19getAvailableClassesIN30pilz_industrial_motion_planner21PlanningContextLoaderEEESt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISA_EEPKNS_11ClassLoaderE[_ZN12class_loader4impl19getAvailableClassesIN30pilz_industrial_motion_planner21PlanningContextLoaderEEESt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISA_EEPKNS_11ClassLoaderE]+0x45): undefined reference to `typeinfo for pilz_industrial_motion_planner::PlanningContextLoader' /usr/bin/ld: CMakeFiles/unittest_planning_context_loaders.dir/src/unittest_planning_context_loaders.cpp.o: in function `pilz_industrial_motion_planner::PlanningContextLoader* class_loader::impl::createInstance<pilz_industrial_motion_planner::PlanningContextLoader>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, class_loader::ClassLoader*)': unittest_planning_context_loaders.cpp:(.text._ZN12class_loader4impl14createInstanceIN30pilz_industrial_motion_planner21PlanningContextLoaderEEEPT_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPNS_11ClassLoaderE[_ZN12class_loader4impl14createInstanceIN30pilz_industrial_motion_planner21PlanningContextLoaderEEEPT_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEPNS_11ClassLoaderE]+0x44): undefined reference to `typeinfo for pilz_industrial_motion_planner::PlanningContextLoader' /usr/bin/ld: warning: creating DT_TEXTREL in a PIE collect2: error: ld returned 1 exit status gmake[2]: *** [test/unit_tests/CMakeFiles/unittest_planning_context_loaders.dir/build.make:363:test/unit_tests/unittest_planning_context_loaders] 错误 1 gmake[1]: *** [CMakeFiles/Makefile2:1007:test/unit_tests/CMakeFiles/unittest_planning_context_loaders.dir/all] 错误 2 /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::getAlgorithm[abi:cxx11]() const' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `typeinfo for pilz_industrial_motion_planner::PlanningContextLoader' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setModel(std::shared_ptr<moveit::core::RobotModel const> const&)' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::PlanningContextLoader()' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::~PlanningContextLoader()' /usr/bin/ld: ../../libplanning_context_loader_lin.so: undefined reference to `pilz_industrial_motion_planner::PlanningContextLoader::setLimits(pilz_industrial_motion_planner::LimitsContainer const&)' collect2: error: ld returned 1 exit status gmake[2]: *** [test/unit_tests/CMakeFiles/unittest_trajectory_generator_common.dir/build.make:365:test/unit_tests/unittest_trajectory_generator_common] 错误 1 gmake[1]: *** [CMakeFiles/Makefile2:709:test/unit_tests/CMakeFiles/unittest_trajectory_generator_common.dir/all] 错误 2 gmake: *** [Makefile:146:all] 错误 2 --- Failed <<< pilz_industrial_motion_planner [38.0s, exited with code 2]
最新发布
07-17
<think>我们正在解决一个编译错误错误信息显示在链接阶段出现了未定义的引用(undefined reference)。具体错误是: ``` /home/fzl/ws_moveit/devel/.private/moveit_planners_ompl/lib/libmoveit_ompl_interface.so.1.0.11: undefined reference to `ompl::geometric::myRRT::~myRRT()' /home/fzl/ws_moveit/devel/.private/moveit_planners_ompl/lib/libmoveit_ompl_interface.so.1.0.11: undefined reference to `ompl::geometric::myRRT::myRRT(std::shared_ptr<ompl::base::SpaceInformation> const&, bool)' ``` 这个错误表明,在链接`libmoveit_ompl_interface.so`时,找不到`myRRT`类的析构函数和构造函数的实现。这通常发生在以下情况: 1. 我们编写了`myRRT.h`和`myRRT.cpp`,但是`myRRT.cpp`没有被正确编译到库中。 2. 在链接时,没有将包含`myRRT`实现的目标文件链接到最终的可执行文件或库中。 根据引用[1]中提供的信息,我们做了以下步骤: 1. 新增了`myRRT.h`和`myRRT.cpp`。 2. 在`planning_context_manager.cpp`中添加了头文件。 3. 修改了`ompl_planning.yaml`配置文件。 但是,在编译过程中出现了链接错误。 ### 解决步骤 #### 1. 检查`myRRT.cpp`是否被正确编译 首先,确保`myRRT.cpp`被添加到正确的目录中,并且被包含在`CMakeLists.txt`中,以便编译器能够编译它。 在`moveit_planners_ompl`包的`CMakeLists.txt`中,应该有一个库(比如`moveit_ompl_interface`)的构建,我们需要将`myRRT.cpp`添加到该库的源文件列表中。 例如,在`CMakeLists.txt`中找到类似这样的部分: ```cmake add_library(moveit_ompl_interface src/ompl_interface.cpp src/ompl_interface_planning_context.cpp ... src/planning_context_manager.cpp # 添加你的myRRT.cpp src/myRRT.cpp ) ``` 如果没有添加,请添加`src/myRRT.cpp`并重新编译。 #### 2. 检查头文件包含 确保在`planning_context_manager.cpp`中正确包含了`myRRT.h`。同时,确保`myRRT.h`中的类声明和`myRRT.cpp`中的实现一致,特别是析构函数和构造函数的声明。 在`myRRT.h`中,应该有以下声明(或类似): ```cpp namespace ompl { namespace geometric { class myRRT : public base::Planner { public: myRRT(const base::SpaceInformationPtr &si, bool addIntermediateStates = false); ~myRRT() override; // ... 其他成员函数 }; } } ``` #### 3. 检查符号导出 如果`myRRT`类是在一个动态库中编译的,确保使用了正确的导出宏。在OMPL中,通常使用`OMPL_CLASS_FORWARD`等宏,但这里我们自定义了一个类,所以需要确保在Windows下(如果适用)使用`__declspec(dllexport)`,但在Linux下通常不需要。不过,在MoveIt中,可能会使用特定的导出宏,比如`MOVEIT_CLASS_FORWARD`。但根据错误来看,我们并没有遇到符号隐藏的问题,而是根本找不到定义,所以重点还是编译和链接。 #### 4. 重新编译 在修改了`CMakeLists.txt`后,需要重新运行`catkin_make`或`catkin build`。由于之前已经编译过,建议先清理再重新编译: ```bash catkin clean moveit_planners_ompl catkin build moveit_planners_ompl ``` 或者,如果使用`catkin_make`: ```bash cd ~/ws_moveit catkin_make --only-pkg-with-deps moveit_planners_ompl ``` #### 5. 检查编译日志 在编译过程中,观察`myRRT.cpp`是否被编译(即是否生成了对应的.o文件)。如果`myRRT.cpp`没有被编译,则说明`CMakeLists.txt`没有正确包含它。 #### 6. 检查链接顺序 在链接`libmoveit_ompl_interface.so`时,需要确保所有依赖的库都正确链接。但是,由于错误是未定义的符号在同一个库中(因为`myRRT`应该是这个库的一部分),所以问题更可能是源文件没有编译进去。 ### 针对pilz_industrial_motion_planner的类似错误 用户提到“我想解决在编译pilz_industrial_motion_planner时的链接错误问题”。虽然错误信息是关于`moveit_planners_ompl`的,但可能用户实际上在编译`pilz_industrial_motion_planner`时遇到了类似的未定义引用错误。 对于`pilz_industrial_motion_planner`的链接错误,同样需要检查: - 是否所有源文件都添加到了`CMakeLists.txt`中。 - 是否在头文件中声明了函数,但在源文件中没有定义(或者源文件没有被编译)。 - 是否链接了所有必要的库。 ### 总结步骤 1. **确认源文件包含**:检查`CMakeLists.txt`,确保新增的`.cpp`文件被添加到正确的目标(库或可执行文件)中。 2. **检查头文件**:确保头文件中的声明和源文件中的定义一致。 3. **清理并重新编译**:清理相关包并重新编译。 4. **查看编译日志**:确认新增的源文件被编译,并且没有其他错误。 如果按照上述步骤操作后问题仍然存在,请提供具体的错误信息以及相关`CMakeLists.txt`的内容,以便进一步诊断。 §§相关问题§§ 1. 如何正确地将新的源文件添加到CMake项目中? 2. 在ROS中,如何清理和重新编译单个包? 3. 链接错误“undefined reference”通常有哪些原因? 4. 如何阅读和理解编译日志?</think>### 解决 pilz_industrial_motion_planner 编译中的未定义引用错误 #### 错误原因分析 编译错误 `undefined reference to ...` 表明链接器无法找到符号定义,通常由以下原因导致: 1. **源文件未参与编译**:新增的 `.cpp` 文件未被添加到构建系统 2. **符号声明/定义不匹配**:头文件中的函数声明与实现不一致 3. **链接顺序错误**:依赖库的链接顺序不当 4. **ABI 兼容性问题**:C++ 编译器版本或符号修饰规则不一致[^1] #### 解决方案步骤 ##### 1. 检查源文件编译配置 在 `pilz_industrial_motion_planner` 的 `CMakeLists.txt` 中确认所有源文件已添加: ```cmake # 在 add_library 或 add_executable 部分检查 add_library(pilz_industrial_motion_planner src/your_new_file.cpp # 确保新增文件在此列出 src/existing_files.cpp ) ``` ##### 2. 验证符号一致性 检查头文件(`.h`)和实现文件(`.cpp`)中的符号声明: ```cpp // 示例:检查析构函数声明一致性 // my_planner.h class MyPlanner { public: virtual ~MyPlanner(); // 声明 }; // my_planner.cpp MyPlanner::~MyPlanner() { ... } // 实现必须存在 ``` ##### 3. 清理并重新编译 执行深度清理后重建: ```bash cd ~/ws_moveit catkin clean pilz_industrial_motion_planner # 清理特定包 catkin build pilz_industrial_motion_planner --no-deps --verbose ``` `--verbose` 参数可显示详细编译日志[^1] ##### 4. 检查链接依赖顺序 在 `CMakeLists.txt` 中调整链接顺序,确保被依赖库在前: ```cmake target_link_libraries(pilz_industrial_motion_planner ${DEPENDENT_LIB_A} # 被依赖的库在前 ${DEPENDENT_LIB_B} ${Boost_LIBRARIES} ) ``` ##### 5. 验证 C++ 标准一致性 在 `CMakeLists.txt` 顶部统一 C++ 标准: ```cmake set(CMAKE_CXX_STANDARD 14) # 与 OMPL 保持一致 set(CMAKE_CXX_STANDARD_REQUIRED ON) ``` #### 验证修复 成功编译的标志: ```bash [100%] Built target pilz_industrial_motion_planner ``` #### 预防措施 1. 使用 `#pragma once` 防止头文件重复包含 2. 遵循 RAII 原则管理资源 3. 定期运行 `catkin lint` 检查包配置 > 注:若问题持续,检查 `pilz_industrial_motion_planner/src` 目录下所有 `.cpp` 文件是否均被添加到 CMake 源文件列表,并确认无同名符号冲突[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值