Skip to content

Commit f36c4f9

Browse files
committed
feat: also lint types that dereference to CStr
For simplicity's sake, this also changes the lint to always suggest `to_bytes`, as it is somewhat hard to find out whether a type could dereference to `CString` (which is what `as_bytes` would require)
1 parent 1fc9441 commit f36c4f9

File tree

4 files changed

+55
-12
lines changed

4 files changed

+55
-12
lines changed

clippy_lints/src/strlen_on_c_strings.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,19 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
4747
&& let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind
4848
&& !recv.span.from_expansion()
4949
&& path.ident.name == sym::as_ptr
50+
&& let typeck = cx.typeck_results()
51+
&& typeck
52+
.expr_ty_adjusted(self_arg)
53+
.peel_refs()
54+
.is_lang_item(cx, LangItem::CStr)
5055
{
51-
let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
52-
let (ty_name, method_name) = if ty.is_diag_item(cx, sym::cstring_type) {
53-
("CString", "as_bytes")
56+
let ty = typeck.expr_ty(self_arg).peel_refs();
57+
let ty_kind = if ty.is_diag_item(cx, sym::cstring_type) {
58+
"`CString` value"
5459
} else if ty.is_lang_item(cx, LangItem::CStr) {
55-
("CStr", "to_bytes")
60+
"`CStr` value"
5661
} else {
57-
return;
62+
"type that dereferences to `CStr`"
5863
};
5964

6065
let ctxt = expr.span.ctxt();
@@ -71,11 +76,11 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
7176
cx,
7277
STRLEN_ON_C_STRINGS,
7378
span,
74-
format!("using `libc::strlen` on a `{ty_name}` value"),
79+
format!("using `libc::strlen` on a {ty_kind}"),
7580
|diag| {
7681
let mut app = Applicability::MachineApplicable;
7782
let val_name = snippet_with_context(cx, self_arg.span, ctxt, "_", &mut app).0;
78-
diag.span_suggestion(span, "try", format!("{val_name}.{method_name}().len()"), app);
83+
diag.span_suggestion(span, "try", format!("{val_name}.to_bytes().len()"), app);
7984
},
8085
);
8186
}

tests/ui/strlen_on_c_strings.fixed

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#![warn(clippy::strlen_on_c_strings)]
2-
#![allow(clippy::manual_c_str_literals)]
2+
#![allow(clippy::manual_c_str_literals, clippy::boxed_local)]
33

44
use libc::strlen;
55
use std::ffi::{CStr, CString};
66

77
fn main() {
88
// CString
99
let cstring = CString::new("foo").expect("CString::new failed");
10-
let _ = cstring.as_bytes().len();
10+
let _ = cstring.to_bytes().len();
1111
//~^ ERROR: using `libc::strlen` on a `CString` value
1212

1313
// CStr
@@ -34,3 +34,13 @@ fn main() {
3434
let _ = unsafe { f(cstr).to_bytes().len() };
3535
//~^ ERROR: using `libc::strlen` on a `CStr` value
3636
}
37+
38+
// make sure we lint types that _adjust_ to `CStr`
39+
fn adjusted(box_cstring: Box<CString>, box_cstr: Box<CStr>, arc_cstring: std::sync::Arc<CStr>) {
40+
let _ = box_cstring.to_bytes().len();
41+
//~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr`
42+
let _ = box_cstr.to_bytes().len();
43+
//~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr`
44+
let _ = arc_cstring.to_bytes().len();
45+
//~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr`
46+
}

tests/ui/strlen_on_c_strings.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![warn(clippy::strlen_on_c_strings)]
2-
#![allow(clippy::manual_c_str_literals)]
2+
#![allow(clippy::manual_c_str_literals, clippy::boxed_local)]
33

44
use libc::strlen;
55
use std::ffi::{CStr, CString};
@@ -34,3 +34,13 @@ fn main() {
3434
let _ = unsafe { strlen(f(cstr).as_ptr()) };
3535
//~^ ERROR: using `libc::strlen` on a `CStr` value
3636
}
37+
38+
// make sure we lint types that _adjust_ to `CStr`
39+
fn adjusted(box_cstring: Box<CString>, box_cstr: Box<CStr>, arc_cstring: std::sync::Arc<CStr>) {
40+
let _ = unsafe { libc::strlen(box_cstring.as_ptr()) };
41+
//~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr`
42+
let _ = unsafe { libc::strlen(box_cstr.as_ptr()) };
43+
//~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr`
44+
let _ = unsafe { libc::strlen(arc_cstring.as_ptr()) };
45+
//~^ ERROR: using `libc::strlen` on a type that dereferences to `CStr`
46+
}

tests/ui/strlen_on_c_strings.stderr

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error: using `libc::strlen` on a `CString` value
22
--> tests/ui/strlen_on_c_strings.rs:10:13
33
|
44
LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstring.as_bytes().len()`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstring.to_bytes().len()`
66
|
77
= note: `-D clippy::strlen-on-c-strings` implied by `-D warnings`
88
= help: to override `-D warnings` add `#[allow(clippy::strlen_on_c_strings)]`
@@ -43,5 +43,23 @@ error: using `libc::strlen` on a `CStr` value
4343
LL | let _ = unsafe { strlen(f(cstr).as_ptr()) };
4444
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `f(cstr).to_bytes().len()`
4545

46-
error: aborting due to 7 previous errors
46+
error: using `libc::strlen` on a type that dereferences to `CStr`
47+
--> tests/ui/strlen_on_c_strings.rs:40:13
48+
|
49+
LL | let _ = unsafe { libc::strlen(box_cstring.as_ptr()) };
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `box_cstring.to_bytes().len()`
51+
52+
error: using `libc::strlen` on a type that dereferences to `CStr`
53+
--> tests/ui/strlen_on_c_strings.rs:42:13
54+
|
55+
LL | let _ = unsafe { libc::strlen(box_cstr.as_ptr()) };
56+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `box_cstr.to_bytes().len()`
57+
58+
error: using `libc::strlen` on a type that dereferences to `CStr`
59+
--> tests/ui/strlen_on_c_strings.rs:44:13
60+
|
61+
LL | let _ = unsafe { libc::strlen(arc_cstring.as_ptr()) };
62+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `arc_cstring.to_bytes().len()`
63+
64+
error: aborting due to 10 previous errors
4765

0 commit comments

Comments
 (0)