Skip to content

Commit 4c6201d

Browse files
Merge #3312
3312: OUT_OF_BOUNDS_INDEXING false negative r=phansch a=JoshMcguigan fixes #3102 Co-authored-by: Josh Mcguigan <[email protected]>
2 parents 44fb29a + 66d3672 commit 4c6201d

File tree

3 files changed

+84
-46
lines changed

3 files changed

+84
-46
lines changed

clippy_lints/src/indexing_slicing.rs

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -108,19 +108,40 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
108108
if let ExprKind::Index(ref array, ref index) = &expr.node {
109109
let ty = cx.tables.expr_ty(array);
110110
if let Some(range) = higher::range(cx, index) {
111+
111112
// Ranged indexes, i.e. &x[n..m], &x[n..], &x[..n] and &x[..]
112113
if let ty::Array(_, s) = ty.sty {
113114
let size: u128 = s.assert_usize(cx.tcx).unwrap().into();
114-
// Index is a constant range.
115-
if let Some((start, end)) = to_const_range(cx, range, size) {
116-
if start > size || end > size {
115+
116+
let const_range = to_const_range(cx, range, size);
117+
118+
if let (Some(start), _) = const_range {
119+
if start > size {
117120
utils::span_lint(
118121
cx,
119122
OUT_OF_BOUNDS_INDEXING,
120-
expr.span,
123+
range.start.map_or(expr.span, |start| start.span),
121124
"range is out of bounds",
122125
);
126+
return;
123127
}
128+
}
129+
130+
if let (_, Some(end)) = const_range {
131+
if end > size {
132+
utils::span_lint(
133+
cx,
134+
OUT_OF_BOUNDS_INDEXING,
135+
range.end.map_or(expr.span, |end| end.span),
136+
"range is out of bounds",
137+
);
138+
return;
139+
}
140+
}
141+
142+
if let (Some(_), Some(_)) = const_range {
143+
// early return because both start and end are constants
144+
// and we have proven above that they are in bounds
124145
return;
125146
}
126147
}
@@ -161,34 +182,34 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
161182
}
162183
}
163184

164-
/// Returns an option containing a tuple with the start and end (exclusive) of
165-
/// the range.
185+
/// Returns a tuple of options with the start and end (exclusive) values of
186+
/// the range. If the start or end is not constant, None is returned.
166187
fn to_const_range<'a, 'tcx>(
167188
cx: &LateContext<'a, 'tcx>,
168189
range: Range<'_>,
169190
array_size: u128,
170-
) -> Option<(u128, u128)> {
191+
) -> (Option<u128>, Option<u128>) {
171192
let s = range
172193
.start
173194
.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
174195
let start = match s {
175-
Some(Some(Constant::Int(x))) => x,
176-
Some(_) => return None,
177-
None => 0,
196+
Some(Some(Constant::Int(x))) => Some(x),
197+
Some(_) => None,
198+
None => Some(0),
178199
};
179200

180201
let e = range
181202
.end
182203
.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
183204
let end = match e {
184205
Some(Some(Constant::Int(x))) => if range.limits == RangeLimits::Closed {
185-
x + 1
206+
Some(x + 1)
186207
} else {
187-
x
208+
Some(x)
188209
},
189-
Some(_) => return None,
190-
None => array_size,
210+
Some(_) => None,
211+
None => Some(array_size),
191212
};
192213

193-
Some((start, end))
214+
(start, end)
194215
}

tests/ui/indexing_slicing.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,9 @@ fn main() {
9191
x[M]; // Ok, should not produce stderr.
9292
v[N];
9393
v[M];
94+
95+
// issue 3102
96+
let num = 1;
97+
&x[num..10]; // should trigger out of bounds error
98+
&x[10..num]; // should trigger out of bounds error
9499
}

tests/ui/indexing_slicing.stderr

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,18 @@ error: slicing may panic.
4848
= help: Consider using `.get(n..)` or .get_mut(n..)` instead
4949

5050
error: range is out of bounds
51-
--> $DIR/indexing_slicing.rs:30:6
51+
--> $DIR/indexing_slicing.rs:30:11
5252
|
5353
30 | &x[..=4];
54-
| ^^^^^^^
54+
| ^
5555
|
5656
= note: `-D clippy::out-of-bounds-indexing` implied by `-D warnings`
5757

5858
error: range is out of bounds
59-
--> $DIR/indexing_slicing.rs:31:6
59+
--> $DIR/indexing_slicing.rs:31:11
6060
|
6161
31 | &x[1..5];
62-
| ^^^^^^^
62+
| ^
6363

6464
error: slicing may panic.
6565
--> $DIR/indexing_slicing.rs:32:6
@@ -70,34 +70,34 @@ error: slicing may panic.
7070
= help: Consider using `.get(..n)`or `.get_mut(..n)` instead
7171

7272
error: range is out of bounds
73-
--> $DIR/indexing_slicing.rs:32:6
73+
--> $DIR/indexing_slicing.rs:32:8
7474
|
7575
32 | &x[5..][..10]; // Two lint reports, one for [5..] and another for [..10].
76-
| ^^^^^^
76+
| ^
7777

7878
error: range is out of bounds
79-
--> $DIR/indexing_slicing.rs:33:6
79+
--> $DIR/indexing_slicing.rs:33:8
8080
|
8181
33 | &x[5..];
82-
| ^^^^^^
82+
| ^
8383

8484
error: range is out of bounds
85-
--> $DIR/indexing_slicing.rs:34:6
85+
--> $DIR/indexing_slicing.rs:34:10
8686
|
8787
34 | &x[..5];
88-
| ^^^^^^
88+
| ^
8989

9090
error: range is out of bounds
91-
--> $DIR/indexing_slicing.rs:35:6
91+
--> $DIR/indexing_slicing.rs:35:8
9292
|
9393
35 | &x[5..].iter().map(|x| 2 * x).collect::<Vec<i32>>();
94-
| ^^^^^^
94+
| ^
9595

9696
error: range is out of bounds
97-
--> $DIR/indexing_slicing.rs:36:6
97+
--> $DIR/indexing_slicing.rs:36:12
9898
|
9999
36 | &x[0..=4];
100-
| ^^^^^^^^
100+
| ^
101101

102102
error: slicing may panic.
103103
--> $DIR/indexing_slicing.rs:37:6
@@ -148,46 +148,46 @@ error: slicing may panic.
148148
= help: Consider using `.get(..n)`or `.get_mut(..n)` instead
149149

150150
error: range is out of bounds
151-
--> $DIR/indexing_slicing.rs:60:6
151+
--> $DIR/indexing_slicing.rs:60:12
152152
|
153153
60 | &empty[1..5];
154-
| ^^^^^^^^^^^
154+
| ^
155155

156156
error: range is out of bounds
157-
--> $DIR/indexing_slicing.rs:61:6
157+
--> $DIR/indexing_slicing.rs:61:16
158158
|
159159
61 | &empty[0..=4];
160-
| ^^^^^^^^^^^^
160+
| ^
161161

162162
error: range is out of bounds
163-
--> $DIR/indexing_slicing.rs:62:6
163+
--> $DIR/indexing_slicing.rs:62:15
164164
|
165165
62 | &empty[..=4];
166-
| ^^^^^^^^^^^
166+
| ^
167167

168168
error: range is out of bounds
169-
--> $DIR/indexing_slicing.rs:63:6
169+
--> $DIR/indexing_slicing.rs:63:12
170170
|
171171
63 | &empty[1..];
172-
| ^^^^^^^^^^
172+
| ^
173173

174174
error: range is out of bounds
175-
--> $DIR/indexing_slicing.rs:64:6
175+
--> $DIR/indexing_slicing.rs:64:14
176176
|
177177
64 | &empty[..4];
178-
| ^^^^^^^^^^
178+
| ^
179179

180180
error: range is out of bounds
181-
--> $DIR/indexing_slicing.rs:65:6
181+
--> $DIR/indexing_slicing.rs:65:16
182182
|
183183
65 | &empty[0..=0];
184-
| ^^^^^^^^^^^^
184+
| ^
185185

186186
error: range is out of bounds
187-
--> $DIR/indexing_slicing.rs:66:6
187+
--> $DIR/indexing_slicing.rs:66:15
188188
|
189189
66 | &empty[..=0];
190-
| ^^^^^^^^^^^
190+
| ^
191191

192192
error: indexing may panic.
193193
--> $DIR/indexing_slicing.rs:74:5
@@ -230,10 +230,10 @@ error: slicing may panic.
230230
= help: Consider using `.get(..n)`or `.get_mut(..n)` instead
231231

232232
error: range is out of bounds
233-
--> $DIR/indexing_slicing.rs:78:6
233+
--> $DIR/indexing_slicing.rs:78:8
234234
|
235235
78 | &x[10..][..100]; // Two lint reports, one for [10..] and another for [..100].
236-
| ^^^^^^^
236+
| ^^
237237

238238
error: slicing may panic.
239239
--> $DIR/indexing_slicing.rs:79:6
@@ -267,5 +267,17 @@ error: indexing may panic.
267267
|
268268
= help: Consider using `.get(n)` or `.get_mut(n)` instead
269269

270-
error: aborting due to 37 previous errors
270+
error: range is out of bounds
271+
--> $DIR/indexing_slicing.rs:97:13
272+
|
273+
97 | &x[num..10]; // should trigger out of bounds error
274+
| ^^
275+
276+
error: range is out of bounds
277+
--> $DIR/indexing_slicing.rs:98:8
278+
|
279+
98 | &x[10..num]; // should trigger out of bounds error
280+
| ^^
281+
282+
error: aborting due to 39 previous errors
271283

0 commit comments

Comments
 (0)