Skip to content

Commit 81d8996

Browse files
Add Rust rule for detecting unsafe functions without unsafe blocks (#884)
* Initial plan * Add Rust rule for detecting unsafe functions without unsafe blocks Co-authored-by: HerringtonDarkholme <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: HerringtonDarkholme <[email protected]>
1 parent 7160896 commit 81d8996

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

website/catalog/rust/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ This page curates a list of example ast-grep rules to check and to rewrite Rust
55
<!--@include: ./avoid-duplicated-exports.md-->
66
<!--@include: ./boshen-footgun.md-->
77
<!--@include: ./get-digit-count-in-usize.md-->
8+
<!--@include: ./redundant-unsafe-function.md-->
89
<!--@include: ./rewrite-indoc-macro.md-->
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
## Unsafe Function Without Unsafe Block
2+
3+
* [Playground Link](/playground.html#eyJtb2RlIjoiQ29uZmlnIiwibGFuZyI6InJ1c3QiLCJxdWVyeSI6IntcbiAgZGVzY3JpcHRpb24gPSAkQVxufSIsInJld3JpdGUiOiIiLCJzdHJpY3RuZXNzIjoic21hcnQiLCJzZWxlY3RvciI6ImJpbmRpbmciLCJjb25maWciOiIgIGlkOiByZWR1bmRhbnQtdW5zYWZlLWZ1bmN0aW9uXG4gIGxhbmd1YWdlOiBydXN0XG4gIHNldmVyaXR5OiBlcnJvclxuICBtZXNzYWdlOiBVbnNhZmUgZnVuY3Rpb24gd2l0aG91dCB1bnNhZmUgYmxvY2sgaW5zaWRlXG4gIG5vdGU6IHxcbiAgICBDb25zaWRlciB3aGV0aGVyIHRoaXMgZnVuY3Rpb24gbmVlZHMgdG8gYmUgbWFya2VkIHVuc2FmZSBcbiAgICBvciBpZiB1bnNhZmUgb3BlcmF0aW9ucyBzaG91bGQgYmUgd3JhcHBlZCBpbiBhbiB1bnNhZmUgYmxvY2tcbiAgcnVsZTpcbiAgICBhbGw6XG4gICAgICAtIGtpbmQ6IGZ1bmN0aW9uX2l0ZW1cbiAgICAgIC0gaGFzOlxuICAgICAgICAgIGtpbmQ6IGZ1bmN0aW9uX21vZGlmaWVyc1xuICAgICAgICAgIHJlZ2V4OiBcIl51bnNhZmVcIlxuICAgICAgLSBub3Q6XG4gICAgICAgICAgaGFzOlxuICAgICAgICAgICAga2luZDogdW5zYWZlX2Jsb2NrXG4gICAgICAgICAgICBzdG9wQnk6IGVuZCIsInNvdXJjZSI6IiAgLy8gU2hvdWxkIG1hdGNoIC0gdW5zYWZlIGZ1bmN0aW9uIHdpdGhvdXQgdW5zYWZlIGJsb2NrIChubyByZXR1cm4gdHlwZSlcbiAgdW5zYWZlIGZuIHJlZHVuZGFudF91bnNhZmUoKSB7XG4gICAgICBwcmludGxuIShcIk5vIHVuc2FmZSBvcGVyYXRpb25zIGhlcmVcIik7XG4gIH1cblxuICAvLyBTaG91bGQgbWF0Y2ggLSB1bnNhZmUgZnVuY3Rpb24gd2l0aCByZXR1cm4gdHlwZSwgbm8gdW5zYWZlIGJsb2NrXG4gIHVuc2FmZSBmbiByZWR1bmRhbnRfd2l0aF9yZXR1cm4oKSAtPiBpMzIge1xuICAgICAgbGV0IHggPSA1O1xuICAgICAgeCArIDEwXG4gIH1cblxuICAvLyBTaG91bGQgbWF0Y2ggLSB1bnNhZmUgZnVuY3Rpb24gd2l0aCBjb21wbGV4IHJldHVybiB0eXBlXG4gIHVuc2FmZSBmbiByZWR1bmRhbnRfY29tcGxleF9yZXR1cm4oKSAtPiBSZXN1bHQ8U3RyaW5nLCBzdGQ6OmlvOjpFcnJvcj4ge1xuICAgICAgT2soU3RyaW5nOjpmcm9tKFwic2FmZSBvcGVyYXRpb25cIikpXG4gIH1cblxuICAvLyBTaG91bGQgTk9UIG1hdGNoIC0gdW5zYWZlIGZ1bmN0aW9uIHdpdGggdW5zYWZlIGJsb2NrXG4gIHVuc2FmZSBmbiBwcm9wZXJfdW5zYWZlKCkgLT4gKmNvbnN0IGkzMiB7XG4gICAgICB1bnNhZmUge1xuICAgICAgICAgIGxldCBwdHIgPSAweDEyMzQgYXMgKmNvbnN0IGkzMjtcbiAgICAgICAgICBwdHJcbiAgICAgIH1cbiAgfVxuXG4gIC8vIFNob3VsZCBtYXRjaCAtIHVuc2FmZSBhc3luYyBmdW5jdGlvbiB3aXRob3V0IHVuc2FmZSBibG9ja1xuICB1bnNhZmUgYXN5bmMgZm4gYXN5bmNfcmVkdW5kYW50KCkgLT4gaTMyIHtcbiAgICAgIDQyXG4gIH1cblxuICAvLyBTaG91bGQgbWF0Y2ggLSB1bnNhZmUgY29uc3QgZnVuY3Rpb25cbiAgdW5zYWZlIGNvbnN0IGZuIGNvbnN0X3JlZHVuZGFudCgpIC0+IGkzMiB7XG4gICAgICAxMDBcbiAgfVxuXG4gIC8vIFNob3VsZCBOT1QgbWF0Y2ggLSByZWd1bGFyIGZ1bmN0aW9uXG4gIGZuIHJlZ3VsYXJfZnVuY3Rpb24oKSAtPiBpMzIge1xuICAgICAgNDJcbiAgfSJ9)
4+
5+
### Description
6+
7+
This rule detects functions marked with the `unsafe` keyword that do not contain any `unsafe` blocks in their body.
8+
9+
When a function is marked `unsafe`, it indicates that the function contains operations that the compiler cannot verify as safe. However, if the function body doesn't contain any `unsafe` blocks, it may be unnecessarily marked as `unsafe`. This could be a sign that:
10+
11+
1. The function should not be marked `unsafe` if it doesn't perform any unsafe operations
12+
2. Or if there are unsafe operations, they should be explicitly wrapped in `unsafe` blocks for clarity
13+
14+
This rule helps identify such cases so developers can review whether the `unsafe` marker is truly necessary or if the code needs to be refactored.
15+
16+
### YAML
17+
```yaml
18+
id: redundant-unsafe-function
19+
language: rust
20+
severity: error
21+
message: Unsafe function without unsafe block inside
22+
note: |
23+
Consider whether this function needs to be marked unsafe
24+
or if unsafe operations should be wrapped in an unsafe block
25+
rule:
26+
all:
27+
- kind: function_item
28+
- has:
29+
kind: function_modifiers
30+
regex: "^unsafe"
31+
- not:
32+
has:
33+
kind: unsafe_block
34+
stopBy: end
35+
```
36+
37+
### Example
38+
39+
```rs {2,7,12,24,29}
40+
// Should match - unsafe function without unsafe block (no return type)
41+
unsafe fn redundant_unsafe() {
42+
println!("No unsafe operations here");
43+
}
44+
45+
// Should match - unsafe function with return type, no unsafe block
46+
unsafe fn redundant_with_return() -> i32 {
47+
let x = 5;
48+
x + 10
49+
}
50+
51+
// Should match - unsafe function with complex return type
52+
unsafe fn redundant_complex_return() -> Result<String, std::io::Error> {
53+
Ok(String::from("safe operation"))
54+
}
55+
56+
// Should NOT match - unsafe function with unsafe block
57+
unsafe fn proper_unsafe() -> *const i32 {
58+
unsafe {
59+
let ptr = 0x1234 as *const i32;
60+
ptr
61+
}
62+
}
63+
64+
// Should match - unsafe async function without unsafe block
65+
unsafe async fn async_redundant() -> i32 {
66+
42
67+
}
68+
69+
// Should match - unsafe const function
70+
unsafe const fn const_redundant() -> i32 {
71+
100
72+
}
73+
74+
// Should NOT match - regular function
75+
fn regular_function() -> i32 {
76+
42
77+
}
78+
```
79+
80+
### Contributed by
81+
82+
Inspired by [@hd_nvim's Tweet](https://x.com/hd_nvim/status/1992810384072585397?s=20)

0 commit comments

Comments
 (0)