Multiplying 0x0 * 0xN crashes with EIGEN_USE_BLAS

Summary

Multiplying a 0x0 matrix by a 0-size vector works as expected with Eigen's internal implementation, but when using BLAS it fails with

 BLAS error: Parameter number 7 passed to cblas_sgemv had an invalid value

on OSX with -framework Accelerate, or

 ** On entry to SGEMV  parameter number  6 had an illegal value

on Linux with -lblas.

Although obviously an edge case, this behavior is triggered by the LBFGS solver in cppoptlib, which starts off with with a 0xN matrix for the direction set and does some operations on it that become non-trivial as the optimization progresses.

The error is documented behavior in BLAS. Parameter 6 is LDA, and:

  LDA    - INTEGER.
         On entry, LDA specifies the first dimension of A as
         declared in the calling (sub) program. LDA must be at
         least max( 1, m ).  Unchanged on exit.

Eigen passes rhs.outerStride() as LDA, which is 0 for a 0x0 matrix. And even though m is zero, BLAS is unhappy. It could be fixed by either passing max(1, rhs.outerStride()), or by not calling SGEMV at all if one of the dimensions is zero.

Environment

  • Operating System : OSX and Linux
  • Architecture : x64 and Arm64
  • Eigen Version : 3.4.0
  • Compiler Version : clang 14.0.0
  • Compile Flags : -O2
  • Vector Extension : NEON on OSX-arm64. None on x64

Minimal Example

#define EIGEN_USE_BLAS
#include "Eigen/Dense"
#include <iostream>

int main(int argc, char* argv[])
{
    Eigen::MatrixXf m(0,0);
    Eigen::VectorXf v(0);

    std::cout << "m size = " << m.rows() << "x" << m.cols() << "\n";
    std::cout << "v size = " << v.rows() << "x" << v.cols() << "\n";
    // Crashes below with EIGEN_USE_BLAS
    Eigen::VectorXf p =  (m * v);
    std::cout << "p size = " << p.rows() << "x" << p.cols() << "\n";

    return 0;
}

Steps to reproduce

With the above file as test/eigen_zerosize.cc, it crashes thusly (on OSX):

$ c++ -std=c++20 -O2 -o test/eigen_zerosize test/eigen_zerosize.cc -I /usr/include/eigen3 -framework Accelerate && test/eigen_zerosize
m size = 0x0
v size = 0x1
 BLAS error: Parameter number 7 passed to cblas_sgemv had an invalid valuep size = 0x1

On Linux, it prints the error but keeps going:

$ c++ -std=c++20 -O2 -o test/eigen_zerosize test/eigen_zerosize.cc -I /usr/include/eigen3 -lblas && test/eigen_zerosize
m size = 0x0
v size = 0x1
 ** On entry to SGEMV  parameter number  6 had an illegal value
p size = 0x1

What is the current bug behavior?

Crashes in SGEMV

What is the expected correct behavior?

Should produce a 0-size vector, like Eigen's internal operations

Relevant logs

Anything else that might help

  • Have a plan to fix this issue.