Overflow in size calculations can allow access to invalid memory
LegionMammal978 opened this issue · 6 comments
This program produces a segmentation fault:
/*
[dependencies]
grid = "=0.8.0"
cargo run --release
*/
use grid::Grid;
fn main() {
let grid: Grid<i32> = Grid::new(2, usize::MAX / 2 + 1);
println!("{}", grid.get(0, 0).unwrap());
}
The documentation on Grid::new()
states that it will panic if rows * cols > usize::MAX
. However, it currently only panics in debug mode; in release mode, rows * cols
will silently overflow without panicking. In this example, rows * cols == 0
due to overflow, so Grid::new()
creates a Vec
of 0 elements, and we attempt to read from element 0. Since this is an invalid pointer (an empty Vec
doesn't point to a real allocation), this results in a segmentation fault.
This issue can be fixed by replacing rows * cols
with rows.checked_mul(cols).expect("...")
in Grid::new()
and Grid::init()
.
Thx for reporting. I will fix this as soon as I possible
Also, Grid::init()
fails to set both dimensions to zero if either is zero, causing a segfault:
/*
[dependencies]
grid = "=0.8.0"
*/
use grid::Grid;
fn main() {
let mut grid = Grid::init(0, 1, 0);
grid.push_row(vec![]);
println!("{}", grid.get(0, 0).unwrap()); // segfault
}
I will change the behavior of puh row or col to panic or nop if length of vec is zero. Right now it is wrong. Thx
I will change the behavior of puh row or col to panic or nop if length of vec is zero.
If you're referring to the Vec
storing the additional row or column, it doesn't have to be empty for the issue to occur:
/*
[dependencies]
grid = "=0.8.0"
*/
use grid::Grid;
fn main() {
let mut grid = Grid::init(0, 2, &0);
grid.push_row(vec![&0]);
println!("{}", grid.get(0, 1).unwrap()); // segfault
}
The length check simply doesn't account for a zero-by-nonzero grid, which you probably don't intend to allow.
The init function is wrong here. It should be the same as for the new function. If either rows or cols is zero it should be initialized fully empty
Fixed with 0.8.1