Skip to content

Commit

Permalink
Add a special case for CStr/CString in the improper_ctypes lint
Browse files Browse the repository at this point in the history
Instead of saying to "consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct",
we now tell users to "consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()`
or `CString::into_raw()`" when the type involved is a `CStr` or a `CString`.
  • Loading branch information
Flying-Toast committed Feb 18, 2024
1 parent 1828461 commit 7f67ee3
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 0 deletions.
5 changes: 5 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,11 @@ lint_improper_ctypes_box = box cannot be represented as a single pointer
lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
lint_improper_ctypes_char_reason = the `char` type has no C equivalent
lint_improper_ctypes_cstr_help =
consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()` or `CString::into_raw()`
lint_improper_ctypes_cstr_reason = `CStr`/`CString` do not have a guaranteed layout
lint_improper_ctypes_dyn = trait objects have no C equivalent
lint_improper_ctypes_enum_repr_help =
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
match def.adt_kind() {
AdtKind::Struct | AdtKind::Union => {
if let Some(sym::cstring_type | sym::cstr_type) =
tcx.get_diagnostic_name(def.did())
{
return FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_cstr_reason,
help: Some(fluent::lint_improper_ctypes_cstr_help),
};
}

if !def.repr().c() && !def.repr().transparent() {
return FfiUnsafe {
ty,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,7 @@ symbols! {
crate_visibility_modifier,
crt_dash_static: "crt-static",
csky_target_feature,
cstr_type,
cstring_type,
ctlz,
ctlz_nonzero,
Expand Down
1 change: 1 addition & 0 deletions library/core/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ use crate::str;
/// [str]: prim@str "str"
#[derive(Hash)]
#[stable(feature = "core_c_str", since = "1.64.0")]
#[rustc_diagnostic_item = "cstr_type"]
#[rustc_has_incoherent_inherent_impls]
#[lang = "CStr"]
// `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
Expand Down
26 changes: 26 additions & 0 deletions tests/ui/lint/lint-ctypes-cstr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#![crate_type = "lib"]
#![deny(improper_ctypes, improper_ctypes_definitions)]

use std::ffi::{CStr, CString};

extern "C" {
fn take_cstr(s: CStr);
//~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe
//~| HELP consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()` or `CString::into_raw()`
fn take_cstr_ref(s: &CStr);
//~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe
//~| HELP consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()` or `CString::into_raw()`
fn take_cstring(s: CString);
//~^ ERROR `extern` block uses type `CString`, which is not FFI-safe
//~| HELP consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()` or `CString::into_raw()`
fn take_cstring_ref(s: &CString);
//~^ ERROR `extern` block uses type `CString`, which is not FFI-safe
//~| HELP consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()` or `CString::into_raw()`
}

extern "C" fn rust_take_cstr_ref(s: &CStr) {}
//~^ ERROR `extern` fn uses type `CStr`, which is not FFI-safe
//~| HELP consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()` or `CString::into_raw()`
extern "C" fn rust_take_cstring(s: CString) {}
//~^ ERROR `extern` fn uses type `CString`, which is not FFI-safe
//~| HELP consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()` or `CString::into_raw()`
66 changes: 66 additions & 0 deletions tests/ui/lint/lint-ctypes-cstr.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
error: `extern` block uses type `CStr`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:7:21
|
LL | fn take_cstr(s: CStr);
| ^^^^ not FFI-safe
|
= help: consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()` or `CString::into_raw()`
= note: `CStr`/`CString` do not have a guaranteed layout
note: the lint level is defined here
--> $DIR/lint-ctypes-cstr.rs:2:9
|
LL | #![deny(improper_ctypes, improper_ctypes_definitions)]
| ^^^^^^^^^^^^^^^

error: `extern` block uses type `CStr`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:10:25
|
LL | fn take_cstr_ref(s: &CStr);
| ^^^^^ not FFI-safe
|
= help: consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()` or `CString::into_raw()`
= note: `CStr`/`CString` do not have a guaranteed layout

error: `extern` block uses type `CString`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:13:24
|
LL | fn take_cstring(s: CString);
| ^^^^^^^ not FFI-safe
|
= help: consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()` or `CString::into_raw()`
= note: `CStr`/`CString` do not have a guaranteed layout

error: `extern` block uses type `CString`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:16:28
|
LL | fn take_cstring_ref(s: &CString);
| ^^^^^^^^ not FFI-safe
|
= help: consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()` or `CString::into_raw()`
= note: `CStr`/`CString` do not have a guaranteed layout

error: `extern` fn uses type `CStr`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:21:37
|
LL | extern "C" fn rust_take_cstr_ref(s: &CStr) {}
| ^^^^^ not FFI-safe
|
= help: consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()` or `CString::into_raw()`
= note: `CStr`/`CString` do not have a guaranteed layout
note: the lint level is defined here
--> $DIR/lint-ctypes-cstr.rs:2:26
|
LL | #![deny(improper_ctypes, improper_ctypes_definitions)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: `extern` fn uses type `CString`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:24:36
|
LL | extern "C" fn rust_take_cstring(s: CString) {}
| ^^^^^^^ not FFI-safe
|
= help: consider passing a `std::ffi::c_char` pointer instead, and use `CStr::as_ptr()` or `CString::into_raw()`
= note: `CStr`/`CString` do not have a guaranteed layout

error: aborting due to 6 previous errors

0 comments on commit 7f67ee3

Please sign in to comment.