OUT_OF_BOUNDS_INDEXING fix #3102 false negative

This commit is contained in:
Josh Mcguigan 2018-10-13 13:51:53 -07:00
parent 601cc9d2c5
commit 0f3345e8b2
3 changed files with 66 additions and 23 deletions

View File

@ -111,17 +111,43 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
// Ranged indexes, i.e. &x[n..m], &x[n..], &x[..n] and &x[..] // Ranged indexes, i.e. &x[n..m], &x[n..], &x[..n] and &x[..]
if let ty::Array(_, s) = ty.sty { if let ty::Array(_, s) = ty.sty {
let size: u128 = s.assert_usize(cx.tcx).unwrap().into(); let size: u128 = s.assert_usize(cx.tcx).unwrap().into();
// Index is a constant range.
if let Some((start, end)) = to_const_range(cx, range, size) { match to_const_range(cx, range, size) {
if start > size || end > size { (None, None) => {},
utils::span_lint( (Some(start), None) => {
cx, if start > size {
OUT_OF_BOUNDS_INDEXING, utils::span_lint(
expr.span, cx,
"range is out of bounds", OUT_OF_BOUNDS_INDEXING,
); expr.span,
} "range is out of bounds",
return; );
return;
}
},
(None, Some(end)) => {
if end > size {
utils::span_lint(
cx,
OUT_OF_BOUNDS_INDEXING,
expr.span,
"range is out of bounds",
);
return;
}
},
(Some(start), Some(end)) => {
if start > size || end > size {
utils::span_lint(
cx,
OUT_OF_BOUNDS_INDEXING,
expr.span,
"range is out of bounds",
);
}
// early return because both start and end are constant
return;
},
} }
} }
@ -161,20 +187,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
} }
} }
/// Returns an option containing a tuple with the start and end (exclusive) of /// Returns a tuple of options with the start and end (exclusive) values of
/// the range. /// the range. If the start or end is not constant, None is returned.
fn to_const_range<'a, 'tcx>( fn to_const_range<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>, cx: &LateContext<'a, 'tcx>,
range: Range<'_>, range: Range<'_>,
array_size: u128, array_size: u128,
) -> Option<(u128, u128)> { ) -> (Option<u128>, Option<u128>) {
let s = range let s = range
.start .start
.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c)); .map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
let start = match s { let start = match s {
Some(Some(Constant::Int(x))) => x, Some(Some(Constant::Int(x))) => Some(x),
Some(_) => return None, Some(_) => None,
None => 0, None => Some(0),
}; };
let e = range let e = range
@ -182,13 +208,13 @@ fn to_const_range<'a, 'tcx>(
.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c)); .map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
let end = match e { let end = match e {
Some(Some(Constant::Int(x))) => if range.limits == RangeLimits::Closed { Some(Some(Constant::Int(x))) => if range.limits == RangeLimits::Closed {
x + 1 Some(x + 1)
} else { } else {
x Some(x)
}, },
Some(_) => return None, Some(_) => None,
None => array_size, None => Some(array_size),
}; };
Some((start, end)) (start, end)
} }

View File

@ -91,4 +91,9 @@ fn main() {
x[M]; // Ok, should not produce stderr. x[M]; // Ok, should not produce stderr.
v[N]; v[N];
v[M]; v[M];
// issue 3102
let num = 1;
&x[num..10]; // should trigger out of bounds error
&x[10..num]; // should trigger out of bounds error
} }

View File

@ -267,5 +267,17 @@ error: indexing may panic.
| |
= help: Consider using `.get(n)` or `.get_mut(n)` instead = help: Consider using `.get(n)` or `.get_mut(n)` instead
error: aborting due to 37 previous errors error: range is out of bounds
--> $DIR/indexing_slicing.rs:97:6
|
97 | &x[num..10]; // should trigger out of bounds error
| ^^^^^^^^^^
error: range is out of bounds
--> $DIR/indexing_slicing.rs:98:6
|
98 | &x[10..num]; // should trigger out of bounds error
| ^^^^^^^^^^
error: aborting due to 39 previous errors