Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does returning an element of a copied Matrix3d result in incorrect output when using Clang 3.9?

Compiling the following example with -O2 on Clang 3.9 results in the reproFunction returning garbage (1.9038e+185) when called in main:

Code

double reproFunction(const Eigen::Matrix3d& R_in)
{
  const Eigen::Matrix3d R = R_in;

  Eigen::Matrix3d Q = R.cwiseAbs();

  if(R(1,2) < 2) {
    Eigen::Vector3d n{0, 1, R(1, 2)};
    double s2 = R(1,2);
    s2 /= n.norm();
  }
  return R(1, 2);
}

int main() {
  Eigen::Matrix3d R;
  R = Eigen::Matrix3d::Zero(3,3); 

  // This fails - reproFunction(R) returns 0
  R(1, 2) = 0.7;
  double R12 = reproFunction(R);
  bool are_they_equal = (R12 == R(1,2));
  std::cout << "R12 == R(1,2): " << are_they_equal << std::endl;
  std::cout << "R12: " << R12 << std::endl;
  std::cout << "R(1, 2): " << R(1, 2) << std::endl;
}

Output

R12 == R(1,2): 0
R12: 1.9036e+185
R(1, 2): 0.7

reproFunction, initializes R (which is const) by assignment from R_in. It returns R(1, 2). Between the assignment and the return, reproFunction uses R in several operations, but none of them should be able to change R. Removing any of those operations results in reproFunction returning the correct value.

This behavior does not appear in any of the following cases:

  • The program is compiled with Clang 3.5, Clang 4.0,or g++-5.4.
  • The optimization level is -O1 or lower
  • Eigen 3.2.10 is used instead of Eigen 3.3.3

Now the question: Is this behavior due to a bug I've missed in the code above, a bug in Eigen 3.3.3, or a bug in Clang 3.9?

A self-contained reproduction example can be found at https://github.com/avalenzu/eigen-clang-weirdness.

like image 258
Andrés Valenzuela Avatar asked Aug 02 '17 19:08

Andrés Valenzuela


1 Answers

I could reproduce this with clang 3.9, but not with clang 3.8. I bisected the issue on Eigen's side to this commit from 2016-05-24 21:54:

Bug 256: enable vectorization with unaligned loads/stores. This concerns all architectures and all sizes. This new behavior can be disabled by defining EIGEN_UNALIGNED_VECTORIZE=0

That commit enables vectorized operations on unaligned data.

I still think, this is a bug in clang, but you can work-around it by compiling with

-D EIGEN_UNALIGNED_VECTORIZE=0

Also, Eigen could be 'fixed' by automatically disabling this feature if clang 3.9 is detected as compiler.

like image 118
chtz Avatar answered Oct 21 '22 23:10

chtz