Skip to content

Commit e0b25c5

Browse files
committed
Auto merge of rust-lang#11998 - cocodery:fix/issue11762, r=llogiq
Check whether out of bound when access a known length array with a constant index fixes [Issue#11762](rust-lang/rust-clippy#11762) Issue#11762 points that `Array references with known length are not flagged when indexed out of bounds`. To fix this problem, it is needed to add check for `Expr::Index`. We expand this issue include reference and direct accessing a array. When we access a array with a constant index `off`, and already know the length `size`, if `off >= size`, these code will throw an error, instead rustc's lint checking them or runtime panic happening. changelog: [`out_of_bound_indexing`]: Add check for illegal accessing known length array with a constant index
2 parents dc97526 + 18eb406 commit e0b25c5

10 files changed

+103
-46
lines changed

clippy_lints/src/indexing_slicing.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,23 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
170170
return;
171171
}
172172
// Index is a constant uint.
173-
if constant(cx, cx.typeck_results(), index).is_some() {
173+
if let Some(constant) = constant(cx, cx.typeck_results(), index) {
174+
// only `usize` index is legal in rust array index
175+
// leave other type to rustc
176+
if let Constant::Int(off) = constant
177+
&& let ty::Uint(utype) = cx.typeck_results().expr_ty(index).kind()
178+
&& *utype == ty::UintTy::Usize
179+
&& let ty::Array(_, s) = ty.kind()
180+
&& let Some(size) = s.try_eval_target_usize(cx.tcx, cx.param_env)
181+
{
182+
// get constant offset and check whether it is in bounds
183+
let off = usize::try_from(off).unwrap();
184+
let size = usize::try_from(size).unwrap();
185+
186+
if off >= size {
187+
span_lint(cx, OUT_OF_BOUNDS_INDEXING, expr.span, "index is out of bounds");
188+
}
189+
}
174190
// Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
175191
return;
176192
}

tests/ui-toml/suppress_lint_in_const/test.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
unconditional_panic,
88
clippy::no_effect,
99
clippy::unnecessary_operation,
10-
clippy::useless_vec
10+
clippy::useless_vec,
11+
clippy::out_of_bounds_indexing
1112
)]
1213

1314
const ARR: [i32; 2] = [1, 2];

tests/ui-toml/suppress_lint_in_const/test.stderr

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
error[E0080]: evaluation of `main::{constant#3}` failed
2-
--> $DIR/test.rs:37:14
2+
--> $DIR/test.rs:38:14
33
|
44
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
55
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4
66

77
note: erroneous constant encountered
8-
--> $DIR/test.rs:37:5
8+
--> $DIR/test.rs:38:5
99
|
1010
LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true.
1111
| ^^^^^^^^^^^^^^^^^^^^^^
1212

1313
error: indexing may panic
14-
--> $DIR/test.rs:28:5
14+
--> $DIR/test.rs:29:5
1515
|
1616
LL | x[index];
1717
| ^^^^^^^^
@@ -21,47 +21,47 @@ LL | x[index];
2121
= help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]`
2222

2323
error: indexing may panic
24-
--> $DIR/test.rs:46:5
24+
--> $DIR/test.rs:47:5
2525
|
2626
LL | v[0];
2727
| ^^^^
2828
|
2929
= help: consider using `.get(n)` or `.get_mut(n)` instead
3030

3131
error: indexing may panic
32-
--> $DIR/test.rs:47:5
32+
--> $DIR/test.rs:48:5
3333
|
3434
LL | v[10];
3535
| ^^^^^
3636
|
3737
= help: consider using `.get(n)` or `.get_mut(n)` instead
3838

3939
error: indexing may panic
40-
--> $DIR/test.rs:48:5
40+
--> $DIR/test.rs:49:5
4141
|
4242
LL | v[1 << 3];
4343
| ^^^^^^^^^
4444
|
4545
= help: consider using `.get(n)` or `.get_mut(n)` instead
4646

4747
error: indexing may panic
48-
--> $DIR/test.rs:54:5
48+
--> $DIR/test.rs:55:5
4949
|
5050
LL | v[N];
5151
| ^^^^
5252
|
5353
= help: consider using `.get(n)` or `.get_mut(n)` instead
5454

5555
error: indexing may panic
56-
--> $DIR/test.rs:55:5
56+
--> $DIR/test.rs:56:5
5757
|
5858
LL | v[M];
5959
| ^^^^
6060
|
6161
= help: consider using `.get(n)` or `.get_mut(n)` instead
6262

6363
error[E0080]: evaluation of constant value failed
64-
--> $DIR/test.rs:15:24
64+
--> $DIR/test.rs:16:24
6565
|
6666
LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts.
6767
| ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4

tests/ui/crashes/ice-5497.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
// reduced from rustc issue-69020-assoc-const-arith-overflow.rs
2+
#![allow(clippy::out_of_bounds_indexing)]
3+
24
pub fn main() {}
35

46
pub trait Foo {

tests/ui/crashes/ice-5497.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: this operation will panic at runtime
2-
--> $DIR/ice-5497.rs:9:22
2+
--> $DIR/ice-5497.rs:11:22
33
|
44
LL | const OOB: i32 = [1][1] + T::OOB;
55
| ^^^^^^ index out of bounds: the length is 1 but the index is 1

tests/ui/get_unwrap.fixed

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
unused_mut,
33
clippy::from_iter_instead_of_collect,
44
clippy::get_first,
5-
clippy::useless_vec
5+
clippy::useless_vec,
6+
clippy::out_of_bounds_indexing
67
)]
78
#![warn(clippy::unwrap_used)]
89
#![deny(clippy::get_unwrap)]

tests/ui/get_unwrap.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
unused_mut,
33
clippy::from_iter_instead_of_collect,
44
clippy::get_first,
5-
clippy::useless_vec
5+
clippy::useless_vec,
6+
clippy::out_of_bounds_indexing
67
)]
78
#![warn(clippy::unwrap_used)]
89
#![deny(clippy::get_unwrap)]

tests/ui/get_unwrap.stderr

+31-31
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
2-
--> $DIR/get_unwrap.rs:36:17
2+
--> $DIR/get_unwrap.rs:37:17
33
|
44
LL | let _ = boxed_slice.get(1).unwrap();
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&boxed_slice[1]`
66
|
77
note: the lint level is defined here
8-
--> $DIR/get_unwrap.rs:8:9
8+
--> $DIR/get_unwrap.rs:9:9
99
|
1010
LL | #![deny(clippy::get_unwrap)]
1111
| ^^^^^^^^^^^^^^^^^^
1212

1313
error: used `unwrap()` on an `Option` value
14-
--> $DIR/get_unwrap.rs:36:17
14+
--> $DIR/get_unwrap.rs:37:17
1515
|
1616
LL | let _ = boxed_slice.get(1).unwrap();
1717
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -22,13 +22,13 @@ LL | let _ = boxed_slice.get(1).unwrap();
2222
= help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]`
2323

2424
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
25-
--> $DIR/get_unwrap.rs:37:17
25+
--> $DIR/get_unwrap.rs:38:17
2626
|
2727
LL | let _ = some_slice.get(0).unwrap();
2828
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_slice[0]`
2929

3030
error: used `unwrap()` on an `Option` value
31-
--> $DIR/get_unwrap.rs:37:17
31+
--> $DIR/get_unwrap.rs:38:17
3232
|
3333
LL | let _ = some_slice.get(0).unwrap();
3434
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -37,13 +37,13 @@ LL | let _ = some_slice.get(0).unwrap();
3737
= help: consider using `expect()` to provide a better panic message
3838

3939
error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
40-
--> $DIR/get_unwrap.rs:38:17
40+
--> $DIR/get_unwrap.rs:39:17
4141
|
4242
LL | let _ = some_vec.get(0).unwrap();
4343
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vec[0]`
4444

4545
error: used `unwrap()` on an `Option` value
46-
--> $DIR/get_unwrap.rs:38:17
46+
--> $DIR/get_unwrap.rs:39:17
4747
|
4848
LL | let _ = some_vec.get(0).unwrap();
4949
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,13 +52,13 @@ LL | let _ = some_vec.get(0).unwrap();
5252
= help: consider using `expect()` to provide a better panic message
5353

5454
error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
55-
--> $DIR/get_unwrap.rs:39:17
55+
--> $DIR/get_unwrap.rs:40:17
5656
|
5757
LL | let _ = some_vecdeque.get(0).unwrap();
5858
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_vecdeque[0]`
5959

6060
error: used `unwrap()` on an `Option` value
61-
--> $DIR/get_unwrap.rs:39:17
61+
--> $DIR/get_unwrap.rs:40:17
6262
|
6363
LL | let _ = some_vecdeque.get(0).unwrap();
6464
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -67,13 +67,13 @@ LL | let _ = some_vecdeque.get(0).unwrap();
6767
= help: consider using `expect()` to provide a better panic message
6868

6969
error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
70-
--> $DIR/get_unwrap.rs:40:17
70+
--> $DIR/get_unwrap.rs:41:17
7171
|
7272
LL | let _ = some_hashmap.get(&1).unwrap();
7373
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_hashmap[&1]`
7474

7575
error: used `unwrap()` on an `Option` value
76-
--> $DIR/get_unwrap.rs:40:17
76+
--> $DIR/get_unwrap.rs:41:17
7777
|
7878
LL | let _ = some_hashmap.get(&1).unwrap();
7979
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -82,13 +82,13 @@ LL | let _ = some_hashmap.get(&1).unwrap();
8282
= help: consider using `expect()` to provide a better panic message
8383

8484
error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
85-
--> $DIR/get_unwrap.rs:41:17
85+
--> $DIR/get_unwrap.rs:42:17
8686
|
8787
LL | let _ = some_btreemap.get(&1).unwrap();
8888
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&some_btreemap[&1]`
8989

9090
error: used `unwrap()` on an `Option` value
91-
--> $DIR/get_unwrap.rs:41:17
91+
--> $DIR/get_unwrap.rs:42:17
9292
|
9393
LL | let _ = some_btreemap.get(&1).unwrap();
9494
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -97,13 +97,13 @@ LL | let _ = some_btreemap.get(&1).unwrap();
9797
= help: consider using `expect()` to provide a better panic message
9898

9999
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
100-
--> $DIR/get_unwrap.rs:45:21
100+
--> $DIR/get_unwrap.rs:46:21
101101
|
102102
LL | let _: u8 = *boxed_slice.get(1).unwrap();
103103
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[1]`
104104

105105
error: used `unwrap()` on an `Option` value
106-
--> $DIR/get_unwrap.rs:45:22
106+
--> $DIR/get_unwrap.rs:46:22
107107
|
108108
LL | let _: u8 = *boxed_slice.get(1).unwrap();
109109
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,13 +112,13 @@ LL | let _: u8 = *boxed_slice.get(1).unwrap();
112112
= help: consider using `expect()` to provide a better panic message
113113

114114
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
115-
--> $DIR/get_unwrap.rs:50:9
115+
--> $DIR/get_unwrap.rs:51:9
116116
|
117117
LL | *boxed_slice.get_mut(0).unwrap() = 1;
118118
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice[0]`
119119

120120
error: used `unwrap()` on an `Option` value
121-
--> $DIR/get_unwrap.rs:50:10
121+
--> $DIR/get_unwrap.rs:51:10
122122
|
123123
LL | *boxed_slice.get_mut(0).unwrap() = 1;
124124
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -127,13 +127,13 @@ LL | *boxed_slice.get_mut(0).unwrap() = 1;
127127
= help: consider using `expect()` to provide a better panic message
128128

129129
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
130-
--> $DIR/get_unwrap.rs:51:9
130+
--> $DIR/get_unwrap.rs:52:9
131131
|
132132
LL | *some_slice.get_mut(0).unwrap() = 1;
133133
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_slice[0]`
134134

135135
error: used `unwrap()` on an `Option` value
136-
--> $DIR/get_unwrap.rs:51:10
136+
--> $DIR/get_unwrap.rs:52:10
137137
|
138138
LL | *some_slice.get_mut(0).unwrap() = 1;
139139
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -142,13 +142,13 @@ LL | *some_slice.get_mut(0).unwrap() = 1;
142142
= help: consider using `expect()` to provide a better panic message
143143

144144
error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
145-
--> $DIR/get_unwrap.rs:52:9
145+
--> $DIR/get_unwrap.rs:53:9
146146
|
147147
LL | *some_vec.get_mut(0).unwrap() = 1;
148148
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0]`
149149

150150
error: used `unwrap()` on an `Option` value
151-
--> $DIR/get_unwrap.rs:52:10
151+
--> $DIR/get_unwrap.rs:53:10
152152
|
153153
LL | *some_vec.get_mut(0).unwrap() = 1;
154154
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -157,13 +157,13 @@ LL | *some_vec.get_mut(0).unwrap() = 1;
157157
= help: consider using `expect()` to provide a better panic message
158158

159159
error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
160-
--> $DIR/get_unwrap.rs:53:9
160+
--> $DIR/get_unwrap.rs:54:9
161161
|
162162
LL | *some_vecdeque.get_mut(0).unwrap() = 1;
163163
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vecdeque[0]`
164164

165165
error: used `unwrap()` on an `Option` value
166-
--> $DIR/get_unwrap.rs:53:10
166+
--> $DIR/get_unwrap.rs:54:10
167167
|
168168
LL | *some_vecdeque.get_mut(0).unwrap() = 1;
169169
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -172,13 +172,13 @@ LL | *some_vecdeque.get_mut(0).unwrap() = 1;
172172
= help: consider using `expect()` to provide a better panic message
173173

174174
error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
175-
--> $DIR/get_unwrap.rs:65:17
175+
--> $DIR/get_unwrap.rs:66:17
176176
|
177177
LL | let _ = some_vec.get(0..1).unwrap().to_vec();
178178
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
179179

180180
error: used `unwrap()` on an `Option` value
181-
--> $DIR/get_unwrap.rs:65:17
181+
--> $DIR/get_unwrap.rs:66:17
182182
|
183183
LL | let _ = some_vec.get(0..1).unwrap().to_vec();
184184
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -187,13 +187,13 @@ LL | let _ = some_vec.get(0..1).unwrap().to_vec();
187187
= help: consider using `expect()` to provide a better panic message
188188

189189
error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
190-
--> $DIR/get_unwrap.rs:66:17
190+
--> $DIR/get_unwrap.rs:67:17
191191
|
192192
LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
193193
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `some_vec[0..1]`
194194

195195
error: used `unwrap()` on an `Option` value
196-
--> $DIR/get_unwrap.rs:66:17
196+
--> $DIR/get_unwrap.rs:67:17
197197
|
198198
LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
199199
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -202,25 +202,25 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
202202
= help: consider using `expect()` to provide a better panic message
203203

204204
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
205-
--> $DIR/get_unwrap.rs:76:24
205+
--> $DIR/get_unwrap.rs:77:24
206206
|
207207
LL | let _x: &i32 = f.get(1 + 2).unwrap();
208208
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `&f[1 + 2]`
209209

210210
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
211-
--> $DIR/get_unwrap.rs:79:18
211+
--> $DIR/get_unwrap.rs:80:18
212212
|
213213
LL | let _x = f.get(1 + 2).unwrap().to_string();
214214
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
215215

216216
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
217-
--> $DIR/get_unwrap.rs:82:18
217+
--> $DIR/get_unwrap.rs:83:18
218218
|
219219
LL | let _x = f.get(1 + 2).unwrap().abs();
220220
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `f[1 + 2]`
221221

222222
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
223-
--> $DIR/get_unwrap.rs:99:33
223+
--> $DIR/get_unwrap.rs:100:33
224224
|
225225
LL | let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap();
226226
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut rest[linidx(j, k) - linidx(i, k) - 1]`

tests/ui/indexing_slicing_index.rs

+3
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,7 @@ fn main() {
7474
//~^ ERROR: indexing may panic
7575
v[M];
7676
//~^ ERROR: indexing may panic
77+
78+
let slice = &x;
79+
let _ = x[4];
7780
}

0 commit comments

Comments
 (0)