Destructor of Ref to const VectorXd calls free(nullptr)
Summary
The destructor of an Eigen::Ref<const Eigen::VectorXd> calls free(nullptr).
Environment
- Operating System : Linux
- Architecture : x64
- Eigen Version : Version: 3.4.0-2ubuntu2
- Compiler Version : Gcc 12.3
- Compile Flags : none
- Vector Extension : none
Minimal Example
#include <Eigen/Dense>
#include <malloc.h>
#include <dlfcn.h>
#include <iostream>
int __malloc_calls = 0;
int __free_calls = 0;
bool __register_calls = false;
void reset_counters()
{
__register_calls = true;
__malloc_calls = 0;
__free_calls = 0;
}
std::pair<int, int> get_counters()
{
__register_calls = false;
return std::make_pair(__malloc_calls, __free_calls);
}
void* malloc(size_t sz)
{
static auto libc_malloc = reinterpret_cast<void *(*)(size_t)>(dlsym(RTLD_NEXT, "malloc"));
if(!__register_calls) return libc_malloc(sz);
__malloc_calls++;
return libc_malloc(sz);
}
void free(void *p)
{
static auto libc_free = reinterpret_cast<void(*)(void*)>(dlsym(RTLD_NEXT, "free"));
if (!__register_calls)
return libc_free(p);
__free_calls++;
fprintf(stderr, "free(%p)\n", p);
libc_free(p);
}
int main()
{
Eigen::VectorXd a(10);
std::cerr << "const case: \n";
reset_counters();
{
Eigen::Ref<const Eigen::VectorXd> aref = a;
}
auto ct = get_counters();
std::cerr << "n malloc called " << ct.first << "\n";
std::cerr << "n free called " << ct.second << "\n";
std::cerr << "non-const case: \n";
reset_counters();
{
Eigen::Ref<Eigen::VectorXd> aref = a;
}
ct = get_counters();
std::cerr << "n malloc called " << ct.first << "\n";
std::cerr << "n free called " << ct.second << "\n";
}
Steps to reproduce
- save the MRE as
eigen_ref_calls_free.cpp - compile with
g++ eigen_ref_calls_free.cpp -I/usr/include/eigen3 -ldl - execute with
./a.out - the output is
const case:
free((nil))
n malloc called 0
n free called 1
non-const case:
n malloc called 0
n free called 0
What is the current bug behavior?
The destructor of the Eigen Ref to a const Eigen::VectorXd calls free with null pointer argument. Notice that the non-const version does not call free on destruction.
What is the expected correct behavior?
If an Eigen Ref is not managing any memory (as in this case, where a temporary copy is obviously not generated), I do not expect it interact with the memory manager in any way. Notice that on some systems this actually causes issues. For instance, in the Xenomai3 real-time co-kernel, calls to malloc/free inside a real-time context will cause a mode switch to non-realtime mode.