This forum has been archived. All content is frozen. Please use KDE Discuss instead.

Memory violation: PlainObjectBase as container class member

Tags: None
(comma "," separated)
User avatar
alecjacobson
Registered Member
Posts
26
Karma
0
I have a templated class Container with a member m_F of type Eigen::PlainObjectBase. If I initialize the member by passing a parameter to the constructor of Container to the constructor of m_F in the constuctor initialization list, I get a memory violation. Here's a minimal example:

Code: Select all
#include <Eigen/Core>

template <typename DerivedF>
class Container
{
  public:
    Eigen::PlainObjectBase<DerivedF> m_F;
    Container(const Eigen::PlainObjectBase<DerivedF> & F)
     :m_F(F)
    {
    }
};

int main()
{
  Eigen::MatrixXi A = Eigen::MatrixXi::Random(10000,3);
  Container<Eigen::MatrixXi> C(A);
}



Compiling using clang++ 7.0 with Eigen version 3.2.4 on mac os x, running the result produces:

Code: Select all
malloc: *** error for object 0x7fb1fb80bc00: pointer being freed was not allocated


Replacing the constructor initialization list with a direct assignment by changing the lines

Code: Select all
:m_F(F)
{
}


to

Code: Select all
{
  m_F = F;
}


makes the error go away.

Is there a reason the constructor initialization list initialization of m_F is causing a memory violation?
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
hm, actually you are not supposed to create PlainObjectBase<> objects. As its name stands, PlainObjectBase has been designed as an abstract base class. You should rather declare m_F as a DerivedF object type.
User avatar
alecjacobson
Registered Member
Posts
26
Karma
0
I'm worried about using Derived_F directly because in other situations this seems to result in a memory leak:

http://www.alecjacobson.com/weblog/?p=4413
I recently ran into a frustrating memory leak “gotcha” involving Eigen. The following code compiles

Code: Select all
template <typename Derived>
Eigen::PlainObjectBase<Derived> leaky(
  const Eigen::PlainObjectBase<Derived> & A)
{
  Derived B = A;
  return B;
}

int main(int argc, char * argv[])
{
  Eigen::MatrixXd A(10000,1);
  Eigen::MatrixXd B = leaky(A);
}


but causes a memory leak (without any warnings/asserts from Eigen):

Code: Select all
.main(33789,0x7fff7bb2d300) malloc: *** error for object 0x7f9ed188da00: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug


The problem seems to be the cast happening in the return. Changing the return type of leaky to Derived:

Code: Select all
template <typename Derived>
Derived leaky(
  const Eigen::PlainObjectBase<Derived> & A)
[/cpde]

fixes the issue. Or it could be fixed by changing the type of B inside leaky to Eigen::PlainObjectBase<Derived>.

[code]
  Eigen::PlainObjectBase<Derived> B = A;


Is this use of PlainObjectBase also discouraged? (It would be convenient if the code didn't compile rather than crash with memory violations, if possible).
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
Right, the core of the problem is still the same: this code creates a PlainObjectBase<Derived> object which is is not a Derived one. leaky() should rather return a Derived object. This will also make it faster thanks to RVO (https://en.wikipedia.org/wiki/Return_value_optimization).

I'll think about a way to disable the compilation of such code, but I cannot think about an easy solution right now. Maybe it will be simpler to fix these usages, even though they are not recommended...
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
Looks like these issues have already been solved in default branch (3.3-alpha1).
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
I fixed it in 3.2 as well because many variants did worked (e.g, by passing PlainObjectBase ctor, multiplying the argument by 1, calling .block on the full matrix, etc.). But this possibility might be disabled in the future...

https://bitbucket.org/eigen/eigen/commits/f4ba6a8d1036/
Branch: 3.2
Summary: Add PlainObjectBase copy ctor from PlainObjectBase and DenseBase objects. (manual backport from default branch, fix segfault when creating PlainObjectBase object, though such an usage is not recommended at all)


Bookmarks



Who is online

Registered users: Bing [Bot], Google [Bot], q.ignora, watchstar