Undefined behavior for block operations on zero-size matrices

Summary

Block operations for non-zero block offsets of an empty matrix perform pointer arithmetic on null pointers, which is undefined behavior in C++.

As of Clang 10, this is now detected by UBSan.

Refer to https://reviews.llvm.org/D67122 for an explanation of the C++ specification, or the first bullet point in Clanga 10 Release Notes for more info.

Environment

  • Operating System : Linux
  • Architecture : x64
  • Eigen Version : trunk
  • Compiler Version : Clang 14 (anything 10 or more)
  • Compile Flags : -O2 -fsanitize=undefined
  • Vector Extension : None

Minimal Example

The following code should be a no-op, but in fact triggers undefined behavior per the C++ standard.

#include <Eigen/Core>
int main() {
  Eigen::MatrixXd A(6, 0);
  A.row(2).setZero();
  return 0;
}

See Clang repro on godbolt: https://godbolt.org/z/7ch9a6x7v

Steps to reproduce

Compile and run the above snippet, using clang++-14 --std=c++17 -O2 -g -fsanitize=undefined snip.cc or similar.

What is the current bug behavior?

/opt/compiler-explorer/libs/eigen/vtrunk/Eigen/src/Core/Block.h:349:25: runtime error: applying non-zero offset 16 to null pointer
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /opt/compiler-explorer/libs/eigen/vtrunk/Eigen/src/Core/Block.h:349:25 in ...

What is the expected correct behavior?

Program returns zero, no error messages.

Anything else that might help

Here is where things go wrong:

https://gitlab.com/libeigen/eigen/-/blob/c2f15edc43367c3a11aacbb51c7431ccb5a31bb5/Eigen/src/Core/Block.h#L349-350

In this case, we have xpr.data() == nullptr (because there is no storage for an empty matrix), yet when we have i > 0, we're using nullptr like an array and offsetting into it. That is UB.

Edited by Jeremy Nimmer