简体   繁体   English

单独编译库源文件时单元测试中的 Seg 错误

[英]Seg fault in unit tests when library source files are compiled separately

I'm writing a small library and have until now added the library source file directly with the unit test in the add_executable command, similarly to below:我正在编写一个小型库,直到现在直接在add_executable命令中使用单元测试添加库源文件,类似于以下内容:

CMakeLists.txt (Resulting executable OK) CMakeLists.txt(生成的可执行文件OK)

cmake_minimum_required(VERSION 3.0)
set(CMAKE_CXX_STANDARD 17) 
find_package(Eigen3 REQUIRED)
find_package(GTSAM 4.0.2 REQUIRED)

add_executable(my_test test/unit_test.cpp src/my_lib.cpp)
target_include_directories(my_test PUBLIC include ${EIGEN3_INCLUDE_DIR} ${GTSAM_INCLUDE_DIR})
target_link_libraries(my_test PUBLIC gtsam)

Everything worked fine until I created an actual library and linked the unit test, similarly to below:一切正常,直到我创建了一个实际的库并链接了单元测试,类似于下面:

CMakeLists.txt (Resulting executable not OK) CMakeLists.txt(生成的可执行文件不正常)

cmake_minimum_required(VERSION 3.0)
set(CMAKE_CXX_STANDARD 17) 

find_package(Eigen3 REQUIRED)
add_library(my_lib STATIC src/my_lib.cpp)
target_include_directories(my_lib PRIVATE include ${EIGEN3_INCLUDE_DIR})

find_package(GTSAM 4.0.2 REQUIRED)
add_executable(my_test test/unit_test.cpp)
target_include_directories(my_test PUBLIC include ${EIGEN3_INCLUDE_DIR} ${GTSAM_INCLUDE_DIR})
target_link_libraries(my_test PUBLIC gtsam my_lib)

Now, however, the test seg faults.但是,现在测试段出现故障。 valgrind reports the following: valgrind报告以下内容:

==18501== Memcheck, a memory error detector
==18501== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==18501== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==18501== Command: ./my_test
==18501==
==18501== Invalid read of size 8
==18501==    at 0x509CFBB: gtsam::noiseModel::Diagonal::Sigmas(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, bool) (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4F3C713: _GLOBAL__sub_I_lago.cpp (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4010732: call_init (dl-init.c:72)
==18501==    by 0x4010732: _dl_init (dl-init.c:119)
==18501==    by 0x40010C9: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)
==18501==  Address 0x7241df8 is 8 bytes before a block of size 8 alloc'd
==18501==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18501==    by 0x4ED9FD: Eigen::internal::aligned_malloc(unsigned long) (Memory.h:159)
==18501==    by 0x507875B: Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >::resize(long, long) [clone .constprop.1340] (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x5085698: Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >::PlainObjectBase<Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<double>, Eigen::Matrix<double, -1, 1, 0, -1, 1> > >(Eigen::DenseBase<Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<double>, Eigen::Matrix<double, -1, 1, 0, -1, 1> > > const&) (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x509CFA2: gtsam::noiseModel::Diagonal::Sigmas(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, bool) (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4F3C713: _GLOBAL__sub_I_lago.cpp (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4010732: call_init (dl-init.c:72)
==18501==    by 0x4010732: _dl_init (dl-init.c:119)
==18501==    by 0x40010C9: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)
==18501==
==18501== Invalid read of size 8
==18501==    at 0x4F3C71D: _GLOBAL__sub_I_lago.cpp (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4010732: call_init (dl-init.c:72)
==18501==    by 0x4010732: _dl_init (dl-init.c:119)
==18501==    by 0x40010C9: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)
==18501==  Address 0x7241da8 is 8 bytes before a block of size 8 alloc'd
==18501==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18501==    by 0x4ED9FD: Eigen::internal::aligned_malloc(unsigned long) (Memory.h:159)
==18501==    by 0x51492E1: Eigen::Matrix<double, -1, 1, 0, -1, 1>::Matrix<int>(int const&) [clone .constprop.1305] (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4F3C6F4: _GLOBAL__sub_I_lago.cpp (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4010732: call_init (dl-init.c:72)
==18501==    by 0x4010732: _dl_init (dl-init.c:119)
==18501==    by 0x40010C9: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)
==18501==
==18501== Invalid read of size 8
==18501==    at 0x509CDD1: gtsam::noiseModel::Diagonal::Variances(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, bool) (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4F3C77A: _GLOBAL__sub_I_lago.cpp (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4010732: call_init (dl-init.c:72)
==18501==    by 0x4010732: _dl_init (dl-init.c:119)
==18501==    by 0x40010C9: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)
==18501==  Address 0x72420f8 is 8 bytes before a block of size 24 alloc'd
==18501==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18501==    by 0x4ED9FD: Eigen::internal::aligned_malloc(unsigned long) (Memory.h:159)
==18501==    by 0x509A53B: Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >::resize(long, long) [clone .constprop.1216] (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x50A4A0A: Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >::PlainObjectBase<Eigen::CwiseUnaryOp<Eigen::internal::scalar_sqrt_op<double>, Eigen::Matrix<double, -1, 1, 0, -1, 1> const> >(Eigen::DenseBase<Eigen::CwiseUnaryOp<Eigen::internal::scalar_sqrt_op<double>, Eigen::Matrix<double, -1, 1, 0, -1, 1> const> > const&) (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x509CD63: gtsam::noiseModel::Diagonal::Variances(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, bool) (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4F3C77A: _GLOBAL__sub_I_lago.cpp (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4010732: call_init (dl-init.c:72)
==18501==    by 0x4010732: _dl_init (dl-init.c:119)
==18501==    by 0x40010C9: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)
==18501== Invalid read of size 8
==18501==    at 0x4F3C784: _GLOBAL__sub_I_lago.cpp (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4010732: call_init (dl-init.c:72)
==18501==    by 0x4010732: _dl_init (dl-init.c:119)
==18501==    by 0x40010C9: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)
==18501==  Address 0x7242098 is 8 bytes before a block of size 24 alloc'd
==18501==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18501==    by 0x4ED9FD: Eigen::internal::aligned_malloc(unsigned long) (Memory.h:159)
==18501==    by 0x513A304: Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::DenseBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&) (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4F3C766: _GLOBAL__sub_I_lago.cpp (in /usr/local/lib/libgtsam.so.4.0.2)
==18501==    by 0x4010732: call_init (dl-init.c:72)
==18501==    by 0x4010732: _dl_init (dl-init.c:119)
==18501==    by 0x40010C9: ??? (in /lib/x86_64-linux-gnu/ld-2.27.so)
==18501==
test_orient: /usr/local/include/eigen3/Eigen/src/Core/DenseStorage.h:128: Eigen::internal::plain_array<T, Size, MatrixOrArrayOptions, 32>::plain_array() [with T = double; int Size = 4; int MatrixOrArrayOptions = 0]: Assertion `(internal::UIntPtr(eigen_unaligned_array_assert_workaround_gcc47(array)) & (31)) == 0 && "this assertion is explained here: " "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" " **** READ THIS WEB PAGE !!! ****"' failed.
==18501==
==18501== Process terminating with default action of signal 6 (SIGABRT)
==18501==    at 0x5F95E97: raise (raise.c:51)
==18501==    by 0x5F97800: abort (abort.c:79)
==18501==    by 0x5F87399: __assert_fail_base (assert.c:92)
==18501==    by 0x5F87411: __assert_fail (assert.c:101)
==18501==    by 0x4D98AE: Eigen::internal::plain_array<double, 4, 0, 32>::plain_array() (DenseStorage.h:128)
==18501==    by 0x4D78AD: Eigen::DenseStorage<double, 4, 4, 1, 0>::DenseStorage() (DenseStorage.h:187)
==18501==    by 0x4D61C7: Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 1, 0, 4, 1> >::PlainObjectBase() (PlainObjectBase.h:484)
==18501==    by 0x4D4DBB: Eigen::Matrix<double, 4, 1, 0, 4, 1>::Matrix() (Matrix.h:259)
==18501==    by 0x4ECF6A: orient::quaternionFromAngleAxis(Eigen::Matrix<double, 3, 1, 0, 3, 1> const&) (from_angle_axis.cpp:56)
==18501==    by 0x4D21C4: ____C_A_T_C_H____T_E_S_T____10() (from_angle_axis_test.cpp:95)
==18501==    by 0x3F5A43: Catch::TestInvokerAsFunction::invoke() const (catch2.hpp:14054)
==18501==    by 0x3F50A2: Catch::TestCase::invoke() const (catch2.hpp:13947)
==18501==
==18501== HEAP SUMMARY:
==18501==     in use at exit: 42,110 bytes in 347 blocks
==18501==   total heap usage: 4,871 allocs, 4,524 frees, 507,954 bytes allocated
==18501==
==18501== LEAK SUMMARY:
==18501==    definitely lost: 64 bytes in 4 blocks
==18501==    indirectly lost: 0 bytes in 0 blocks
==18501==      possibly lost: 0 bytes in 0 blocks
==18501==    still reachable: 42,046 bytes in 343 blocks
==18501==         suppressed: 0 bytes in 0 blocks
==18501== Rerun with --leak-check=full to see details of leaked memory
==18501==
==18501== For counts of detected and suppressed errors, rerun with: -v
==18501== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)

The link in the Eigen assert makes me none the wiser unfortunately.不幸的是,Eigen 断言中的链接让我变得更聪明。

My question is: Is the seg fault a result of incorrectly linking against either my own library or GTSAM?我的问题是:seg 错误是由于错误地链接到我自己的库或 GTSAM 造成的吗? If so, how can I fix it?如果是这样,我该如何解决? If not, should I assume that there is a bug in my library that manifests itself only in the second case?如果不是,我是否应该假设我的库中存在仅在第二种情况下才表现出来的错误?

EDIT:编辑:

Minimal working example to reproduce:重现的最小工作示例:

include/my_lib.hpp包括/my_lib.hpp

#pragma once
void f();

src/my_lib.cpp src/my_lib.cpp

#include <my_lib.hpp>
#include <unsupported/Eigen/KroneckerProduct>

void f() 
{
  Eigen::Matrix3d A = Eigen::Matrix3d::Random();
  Eigen::Matrix<double, 9, 3> B = Eigen::Matrix<double, 9, 3>::Random();
  Eigen::Matrix3d I = Eigen::Matrix3d::Identity();
  Eigen::Matrix<double, 9, 3> tmp = Eigen::kroneckerProduct(I, A) * B;
}

test/unit_test.cpp测试/unit_test.cpp

#include <my_lib.hpp>
#include <gtsam/base/numericalDerivative.h>

int main()
{
  f();
  return 0;
}

Your library uses Eigen3 library, which is also part of gtsam library used in the tests.您的库使用 Eigen3 库,它也是测试中使用的 gtsam 库的一部分。 You need to make sure that in both cases the same Eigen3 library is used, otherwise subtle bugs could happen (like the one you observe).您需要确保在这两种情况下都使用相同的 Eigen3 库,否则可能会发生细微的错误(如您观察到的错误)。


Technically, your library and gtsam-based test are separate objects files , so they are compiled independently and both of them are correct .从技术上讲,您的库和基于 gtsam 的测试是单独的对象文件,因此它们是独立编译的,并且它们都是正确的。

It is a linker who could perform unwanted optimizations like merging functions from these object files.它是一个linker ,可以执行不需要的优化,例如从这些 object 文件中合并函数。 Eg in case these functions have the same name.例如,如果这些函数具有相同的名称。 If you find a way to forbid such sort of optimizations for the linker, then resulted test could work correctly even in case of incompatible Eigen3 libraries used for your library in by gtsam.如果您找到一种方法来禁止对 linker 进行此类优化,那么即使在 gtsam 用于您的库的 Eigen3 库不兼容的情况下,结果测试也可以正常工作。

However, disabling linker optimizations is a very subtle way from the view of stability of your project.但是,从项目稳定性的角度来看,禁用 linker 优化是一种非常微妙的方法。 Use this way only as the last resort.仅将这种方式用作最后的手段。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM