本征静态库 aligned_free "double free or corruption"
Eigen static lib aligned_free "double free or corruption"
这是 earlier post 的延续。
但这次有一个希望更好的例子。这个简单的测试在设置向量时崩溃了。
我正在使用 Ubuntu 20.04、gcc 9.3.0、c++17、eigen 3.3.7
main.cpp
#include <iostream>
#include <memory>
#include "C.h"
using namespace std;
class B {
public:
C c;
B() {
cout << (uint64_t)this << endl;
}
~B(){}
};
int main() {
shared_ptr<B> b = make_shared<B>();
b->c.v = VectorXd(5); // << crashes here
// SIGABRT on `Eigen::internal::aligned_free` when trying to do `std::free()`
return 0;
}
Class C 作为静态库链接。静态库在 Release 模式下编译 (--std=c++17 -DNDEBUG -O3
),而主程序在 Debug 模式下 运行 - 没有优化。
如果Debug中静态库和主程序都是运行,那么就没有crash。
此外,如果它们在 Release 中都是 运行,则不会发生崩溃。只有在Release编译静态库,Debug编译主程序时才会出现此问题
C.h
#pragma once
#include <vector>
#include <Eigen/Core>
using namespace std;
using namespace Eigen;
class C {
public:
VectorXd v;
C();
~C();
};
C.cpp
#include "C.h"
C::C() {
v = VectorXd(5);
}
C::~C() {
}
如果您使用不匹配的体系结构标志 (-m...
flags for gcc) 编译库和主要可执行文件,您可以观察到崩溃。例如,当我编译启用了 avx (-mavx
) 的库和没有启用 avx 的主要可执行文件时,反之亦然,它崩溃了。崩溃也发生在 Eigen 3.4.0 中。此外,它也会在没有优化的情况下发生 (-O0
).
Eigen aligned_malloc()
和 aligned_free()
函数根据 EIGEN_DEFAULT_ALIGN_BYTES
宏的值做不同的事情,例如当AVX(以及其他)被启用或禁用。 Eigen 根据使用的编译器标志自动选择合适的值。因此,如果仅在静态库中启用 AVX,C
的构造函数在内部使用 handmade_aligned_malloc()
,它不会直接返回 malloc()
接收到的指针,而是将其移动一点以确保正确对齐。另一方面,从可执行文件(在没有 AVX 的情况下编译)中为 C::v
分配一个新值将首先尝试通过调用 b->c.v.~VectorXd()
来释放内存,然后最终只调用 free()
而不是 handmade_aligned_free()
。因此,free()
接收到的地址不指向已分配内存的开头,从而导致崩溃。
当然,如果您在可执行文件中启用 AVX 而在库中禁用它,则会得到对 malloc()
和 handmade_aligned_free()
的不匹配调用,也会导致崩溃。
解决方案很简单:确保使用相同的体系结构标志编译静态库和可执行文件。如果出于某种原因这是不可能的,请确保创建和销毁始终发生在同一组件中。例如,您可以将 C::v
设为私有并仅允许通过 C.cpp
文件中实现的函数对其进行修改。
注意:您的 other post 有点不同,因为它不涉及动态内存管理,而目前 post 您使用的 VectorXd
确实使用动态内存管理。
注2:描述的问题与std::shared_ptr
的使用无关。但是对于 3.4.0 之前的 Eigen 版本,您可能需要使用 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
来确保指针 b
正确对齐,而不管体系结构和 C++17;至少最初的 Eigen issue 只为 3.4.0 实现。但我可能错了。
这是 earlier post 的延续。
但这次有一个希望更好的例子。这个简单的测试在设置向量时崩溃了。
我正在使用 Ubuntu 20.04、gcc 9.3.0、c++17、eigen 3.3.7
main.cpp
#include <iostream>
#include <memory>
#include "C.h"
using namespace std;
class B {
public:
C c;
B() {
cout << (uint64_t)this << endl;
}
~B(){}
};
int main() {
shared_ptr<B> b = make_shared<B>();
b->c.v = VectorXd(5); // << crashes here
// SIGABRT on `Eigen::internal::aligned_free` when trying to do `std::free()`
return 0;
}
Class C 作为静态库链接。静态库在 Release 模式下编译 (--std=c++17 -DNDEBUG -O3
),而主程序在 Debug 模式下 运行 - 没有优化。
如果Debug中静态库和主程序都是运行,那么就没有crash。
此外,如果它们在 Release 中都是 运行,则不会发生崩溃。只有在Release编译静态库,Debug编译主程序时才会出现此问题
C.h
#pragma once
#include <vector>
#include <Eigen/Core>
using namespace std;
using namespace Eigen;
class C {
public:
VectorXd v;
C();
~C();
};
C.cpp
#include "C.h"
C::C() {
v = VectorXd(5);
}
C::~C() {
}
如果您使用不匹配的体系结构标志 (-m...
flags for gcc) 编译库和主要可执行文件,您可以观察到崩溃。例如,当我编译启用了 avx (-mavx
) 的库和没有启用 avx 的主要可执行文件时,反之亦然,它崩溃了。崩溃也发生在 Eigen 3.4.0 中。此外,它也会在没有优化的情况下发生 (-O0
).
Eigen aligned_malloc()
和 aligned_free()
函数根据 EIGEN_DEFAULT_ALIGN_BYTES
宏的值做不同的事情,例如当AVX(以及其他)被启用或禁用。 Eigen 根据使用的编译器标志自动选择合适的值。因此,如果仅在静态库中启用 AVX,C
的构造函数在内部使用 handmade_aligned_malloc()
,它不会直接返回 malloc()
接收到的指针,而是将其移动一点以确保正确对齐。另一方面,从可执行文件(在没有 AVX 的情况下编译)中为 C::v
分配一个新值将首先尝试通过调用 b->c.v.~VectorXd()
来释放内存,然后最终只调用 free()
而不是 handmade_aligned_free()
。因此,free()
接收到的地址不指向已分配内存的开头,从而导致崩溃。
当然,如果您在可执行文件中启用 AVX 而在库中禁用它,则会得到对 malloc()
和 handmade_aligned_free()
的不匹配调用,也会导致崩溃。
解决方案很简单:确保使用相同的体系结构标志编译静态库和可执行文件。如果出于某种原因这是不可能的,请确保创建和销毁始终发生在同一组件中。例如,您可以将 C::v
设为私有并仅允许通过 C.cpp
文件中实现的函数对其进行修改。
注意:您的 other post 有点不同,因为它不涉及动态内存管理,而目前 post 您使用的 VectorXd
确实使用动态内存管理。
注2:描述的问题与std::shared_ptr
的使用无关。但是对于 3.4.0 之前的 Eigen 版本,您可能需要使用 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
来确保指针 b
正确对齐,而不管体系结构和 C++17;至少最初的 Eigen issue 只为 3.4.0 实现。但我可能错了。