fix missing_asserts_for_indexing ignores match for length#17400
fix missing_asserts_for_indexing ignores match for length#17400wasd243 wants to merge 5 commits into
missing_asserts_for_indexing ignores match for length#17400Conversation
…arantees the index is in bounds
|
Thanks for the pull request, and welcome!You should hear from one of our reviewers after this PR is reviewed by at least 2 reviewers from the community Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (
|
|
Lintcheck changes for cd5f376
This comment will be updated if you push new changes |
| && is_slice_len_expr(cx, scrutinee, slice) | ||
| && match_arms_bound_len(cx, index_expr, arms) | ||
| { | ||
| return arms.iter().any(|arm| is_wild(arm.pat)); |
There was a problem hiding this comment.
This assumes that if we have a wildcard anywhere, then the entire match is safe, even if we are accessing indexes we can't safely assume.
fn foo(supported: &[u8]) {
match supported.len() {
0 => {},
1 => {},
2 => println!("{} {}", supported[0], supported[2]),
_ => println!("{} {}", supported[0], supported[2]),
}
}There was a problem hiding this comment.
Fixed -- literal arms now require index < n (the arm pins len to exactly n), instead of the shared index <= max check.
Lints now:
match supported.len() {
0 => {},
1 => {},
2 => println!("{} {}", supported[2], supported[3]), // both out of bounds for len == 2 → lints
_ => {},
}The example doesn't lint but for a pre-existing reason unrelated to the suppression:
match supported.len() {
0 => {},
1 => {},
2 => println!("{} {}", supported[0], supported[2]), // [0] in bounds → suppressed; [2] NOT suppressed
_ => println!("{} {}", supported[0], supported[2]), // both in bounds (len >= 3) → suppressed
}Co-authored-by: Gri-ffin <82527700+Gri-ffin@users.noreply.github.com>
Fixes #17398
missing_asserts_for_indexingpreviously ignoredmatchexpressions, so indexing inside amatchon the slice's length was linted even when the match arms already guarantee the indices are in bounds. For example:Here the
0and1arms rule out all lengths below 2, so the indexing in the wildcard arm cannot fail and the bounds checks are already elided without anassert!.This PR suppresses the lint for an index inside a
matchonslice.len()when the non-wildcard arms are integer literals contiguously covering0..=max(so the wildcard arm implieslen > max) and the index is at mostmax.The check is deliberately conservative and falls back to linting as before when:
0..=max(e.g.5 => .., _ => .., where_can still be0)0 | 1 => ..is safe in principle but not analyzed)One behavioral note: suppression is per-index. If a
matchguaranteeslen > 1but the wildcard arm indexes[0],[1]and[2], only[2]remains unsuppressed, which is equivalent to a single unchecked access and therefore doesn't lint (consistent with the lint never firing on single accesses).changelog: [
missing_asserts_for_indexing]: fix false positive when amatchon the slice length guarantees the indices are in bounds