Open
Description
Some functions (including solve_inplace
but probably many others) are missing checks that the input arrays have matching shapes. As a result, the current implementation of solve_inplace
can lead to buffer overflow if the shapes don't match (e.g. if the number of rows in b
is less than the number of rows/columns in a
).
Example with ndarray
0.12 and ndarray-linalg
0.10:
extern crate ndarray;
extern crate ndarray_linalg;
use ndarray::array;
use ndarray::prelude::*;
use ndarray_linalg::solve::Solve;
fn main() {
let a = array![[1., 2.], [3., 4.]];
let mut b = array![1.];
// This is a read of uninitialized memory one past the end of `b`. This is
// undefined behavior, but the point of this print statement is to show
// that calling `a.solve_inplace(&mut b)` changes the value of the element
// one past the end of `b`.
//
// On my system, this prints `0`, but it could print anything because the
// memory is uninitialized.
println!("{}", unsafe { *b.as_ptr().wrapping_offset(1) } );
// This should panic or return an error because `a` is `2x2` and `b` has
// length `1`.
a.solve_inplace(&mut b).unwrap();
// Prints `[-1.9999999999999998]` on my system, which corresponds to the
// first element in the solution if `b` was `array![1., 0.]`.
println!("{}", b);
// This is another read of uninitialized memory one past the end of `b`.
// This is undefined behavior, but the point of this print statement is to
// show that calling `a.solve_inplace(&mut b)` changes the value of the
// element one past the end of `b`.
//
// On my system, this prints `1.4999999999999998`, which corresponds to the
// second element in the solution if `b` was `array![1., 0.]`.
println!("{}", unsafe { *b.as_ptr().wrapping_offset(1) } );
}