Skip to content

Commit f8aecf5

Browse files
committed
Lint against invalid POSIX function definitions
1 parent fd07dbf commit f8aecf5

11 files changed

Lines changed: 302 additions & 4 deletions

File tree

compiler/rustc_hir/src/lang_items.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,14 @@ language_item_table! {
455455
MemCmp, sym::memcmp_fn, memcmp_fn, Target::Fn, GenericRequirement::None;
456456
Bcmp, sym::bcmp_fn, bcmp_fn, Target::Fn, GenericRequirement::None;
457457
StrLen, sym::strlen_fn, strlen_fn, Target::Fn, GenericRequirement::None;
458+
Open, sym::open_fn, open_fn, Target::Fn, GenericRequirement::None;
459+
Read, sym::read_fn, read_fn, Target::Fn, GenericRequirement::None;
460+
Write, sym::write_fn, write_fn, Target::Fn, GenericRequirement::None;
461+
Close, sym::close_fn, close_fn, Target::Fn, GenericRequirement::None;
462+
Malloc, sym::malloc_fn, malloc_fn, Target::Fn, GenericRequirement::None;
463+
Realloc, sym::realloc_fn, realloc_fn, Target::Fn, GenericRequirement::None;
464+
Free, sym::free_fn, free_fn, Target::Fn, GenericRequirement::None;
465+
Exit, sym::exit_fn, exit_fn, Target::Fn, GenericRequirement::None;
458466
}
459467

460468
/// The requirement imposed on the generics of a lang item

compiler/rustc_hir/src/weak_lang_items.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,12 @@ weak_only_lang_items! {
4747
MemCmp,
4848
Bcmp,
4949
StrLen,
50+
Open,
51+
Read,
52+
Write,
53+
Close,
54+
Malloc,
55+
Realloc,
56+
Free,
57+
Exit,
5058
}

compiler/rustc_lint/src/runtime_symbols.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{LateContext, LateLintPass, LintContext};
1111

1212
declare_lint! {
1313
/// The `invalid_runtime_symbol_definitions` lint checks the signature of items whose
14-
/// symbol name is a runtime symbol expected by `core` differs significantly from the
14+
/// symbol name is a runtime symbol expected by `core` or `std` differs significantly from the
1515
/// expected signature (like mismatch ABI, mismatch C variadics, mismatch argument count,
1616
/// missing return type, ...).
1717
///
@@ -32,7 +32,8 @@ declare_lint! {
3232
/// standard-library facility or undefined behavior may occur.
3333
///
3434
/// The symbols currently checked are `memcpy`, `memmove`, `memset`, `memcmp`,
35-
/// `bcmp` and `strlen`.
35+
/// `bcmp`, `strlen`, as well as the following POSIX symbols: `open`, `read`, `write`
36+
/// `close`, `malloc`, `realloc`, `free` and `exit`.
3637
///
3738
/// [^1]: https://doc.rust-lang.org/core/index.html#how-to-use-the-core-library
3839
pub INVALID_RUNTIME_SYMBOL_DEFINITIONS,
@@ -42,7 +43,7 @@ declare_lint! {
4243

4344
declare_lint! {
4445
/// The `suspicious_runtime_symbol_definitions` lint checks the signature of items whose
45-
/// symbol name is a runtime symbol expected by `core`.
46+
/// symbol name is a runtime symbol expected by `core` or `std`.
4647
///
4748
/// ### Example
4849
///
@@ -62,7 +63,8 @@ declare_lint! {
6263
/// standard-library facility or undefined behavior may occur.
6364
///
6465
/// The symbols currently checked are `memcpy`, `memmove`, `memset`, `memcmp`,
65-
/// `bcmp` and `strlen`.
66+
/// `bcmp`, `strlen`, as well as the following POSIX symbols: `open`, `read`, `write`
67+
/// `close`, `malloc`, `realloc`, `free` and `exit`.
6668
///
6769
/// [^1]: https://doc.rust-lang.org/core/index.html#how-to-use-the-core-library
6870
pub SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS,
@@ -73,12 +75,22 @@ declare_lint! {
7375
declare_lint_pass!(RuntimeSymbols => [INVALID_RUNTIME_SYMBOL_DEFINITIONS, SUSPICIOUS_RUNTIME_SYMBOL_DEFINITIONS]);
7476

7577
static EXPECTED_SYMBOLS: &[ExpectedSymbol] = &[
78+
// `core` symbols
7679
ExpectedSymbol { symbol: "memcpy", lang: LanguageItems::memcpy_fn },
7780
ExpectedSymbol { symbol: "memmove", lang: LanguageItems::memmove_fn },
7881
ExpectedSymbol { symbol: "memset", lang: LanguageItems::memset_fn },
7982
ExpectedSymbol { symbol: "memcmp", lang: LanguageItems::memcmp_fn },
8083
ExpectedSymbol { symbol: "bcmp", lang: LanguageItems::bcmp_fn },
8184
ExpectedSymbol { symbol: "strlen", lang: LanguageItems::strlen_fn },
85+
// POSIX symbols
86+
ExpectedSymbol { symbol: "open", lang: LanguageItems::open_fn },
87+
ExpectedSymbol { symbol: "read", lang: LanguageItems::read_fn },
88+
ExpectedSymbol { symbol: "write", lang: LanguageItems::write_fn },
89+
ExpectedSymbol { symbol: "close", lang: LanguageItems::close_fn },
90+
ExpectedSymbol { symbol: "malloc", lang: LanguageItems::malloc_fn },
91+
ExpectedSymbol { symbol: "realloc", lang: LanguageItems::realloc_fn },
92+
ExpectedSymbol { symbol: "free", lang: LanguageItems::free_fn },
93+
ExpectedSymbol { symbol: "exit", lang: LanguageItems::exit_fn },
8294
];
8395

8496
#[derive(Copy, Clone, Debug)]

compiler/rustc_span/src/symbol.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ symbols! {
615615
clone_closures,
616616
clone_fn,
617617
clone_from,
618+
close_fn,
618619
closure,
619620
closure_lifetime_binder,
620621
closure_to_fn_coercion,
@@ -898,6 +899,7 @@ symbols! {
898899
exhaustive_integer_patterns,
899900
exhaustive_patterns,
900901
existential_type,
902+
exit_fn,
901903
exp2f16,
902904
exp2f32,
903905
exp2f64,
@@ -1009,6 +1011,7 @@ symbols! {
10091011
format_unsafe_arg,
10101012
fp,
10111013
framework,
1014+
free_fn,
10121015
freeze,
10131016
freeze_impls,
10141017
freg,
@@ -1248,6 +1251,7 @@ symbols! {
12481251
macro_vis_matcher,
12491252
macros_in_extern,
12501253
main,
1254+
malloc_fn,
12511255
managed_boxes,
12521256
manually_drop,
12531257
map,
@@ -1473,6 +1477,7 @@ symbols! {
14731477
on_unmatched_args,
14741478
opaque,
14751479
opaque_module_name_placeholder: "<opaque>",
1480+
open_fn,
14761481
ops,
14771482
opt_out_copy,
14781483
optimize,
@@ -1656,9 +1661,11 @@ symbols! {
16561661
raw_identifiers,
16571662
raw_ref_op,
16581663
re_rebalance_coherence,
1664+
read_fn,
16591665
read_via_copy,
16601666
readonly,
16611667
realloc,
1668+
realloc_fn,
16621669
realtime,
16631670
reason,
16641671
reborrow,
@@ -2359,6 +2366,7 @@ symbols! {
23592366
write_box_via_move,
23602367
write_bytes,
23612368
write_fmt,
2369+
write_fn,
23622370
write_macro,
23632371
write_str,
23642372
write_via_move,

library/std/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@
321321
#![feature(borrowed_buf_init)]
322322
#![feature(bstr)]
323323
#![feature(bstr_internals)]
324+
#![feature(c_size_t)]
324325
#![feature(cast_maybe_uninit)]
325326
#![feature(char_internals)]
326327
#![feature(clone_to_uninit)]

library/std/src/sys/alloc/unix.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,25 @@ use super::{MIN_ALIGN, realloc_fallback};
22
use crate::alloc::{GlobalAlloc, Layout, System};
33
use crate::ptr;
44

5+
// Used by rustc for checking the definitions of other function with the same symbol names
6+
//
7+
// See the `invalid_runtime_symbols_definitions` lint.
8+
#[cfg(not(test))]
9+
mod runtime_symbols {
10+
use core::ffi::{c_size_t, c_void};
11+
12+
unsafe extern "C" {
13+
#[lang = "malloc_fn"]
14+
fn malloc(size: c_size_t) -> *mut c_void;
15+
16+
#[lang = "realloc_fn"]
17+
fn realloc(ptr: *mut c_void, size: c_size_t) -> *mut c_void;
18+
19+
#[lang = "free_fn"]
20+
fn free(ptr: *mut c_void);
21+
}
22+
}
23+
524
#[stable(feature = "alloc_system_type", since = "1.28.0")]
625
unsafe impl GlobalAlloc for System {
726
#[inline]

library/std/src/sys/exit.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,25 @@ cfg_select! {
6868
}
6969
}
7070

71+
#[cfg(not(test))]
72+
cfg_select! {
73+
any(
74+
target_family = "unix",
75+
target_os = "wasi",
76+
) => {
77+
// Used by rustc for checking the definitions of other function with the same symbol names
78+
//
79+
// See the `invalid_runtime_symbols_definitions` lint.
80+
mod runtime_symbols {
81+
unsafe extern "C" {
82+
#[lang = "exit_fn"]
83+
fn exit(status: core::ffi::c_int) -> !;
84+
}
85+
}
86+
}
87+
_ => {}
88+
}
89+
7190
pub fn exit(code: i32) -> ! {
7291
cfg_select! {
7392
target_os = "hermit" => {

library/std/src/sys/fs/unix.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,28 @@ use crate::sys::weak::weak;
100100
use crate::sys::{AsInner, AsInnerMut, FromInner, IntoInner, cvt, cvt_r};
101101
use crate::{mem, ptr};
102102

103+
// Used by rustc for checking the definitions of other function with the same symbol names
104+
//
105+
// See the `invalid_runtime_symbols_definitions` lint.
106+
#[cfg(not(test))]
107+
mod runtime_symbols {
108+
use core::ffi::{c_char, c_int, c_size_t, c_ssize_t, c_void};
109+
110+
unsafe extern "C" {
111+
#[lang = "open_fn"]
112+
fn open(pathname: *const c_char, flags: c_int, ...) -> c_int;
113+
114+
#[lang = "read_fn"]
115+
fn read(fd: c_int, buf: *mut c_void, count: c_size_t) -> c_ssize_t;
116+
117+
#[lang = "write_fn"]
118+
fn write(fd: c_int, buf: *const c_void, count: c_size_t) -> c_ssize_t;
119+
120+
#[lang = "close_fn"]
121+
fn close(fd: c_int) -> c_int;
122+
}
123+
}
124+
103125
pub struct File(FileDesc);
104126

105127
// FIXME: This should be available on Linux with all `target_env`.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// This test makes sure that the following symbols are not linked against
2+
// in a #[no_std] context.
3+
4+
//@ check-pass
5+
6+
#![no_std]
7+
#![crate_type = "lib"]
8+
9+
use core::ffi::{c_char, c_int, c_void};
10+
11+
#[no_mangle]
12+
pub fn open() {}
13+
14+
extern "C" {
15+
pub fn read();
16+
pub fn write();
17+
}
18+
19+
#[no_mangle]
20+
pub static close: () = ();
21+
22+
extern "C" {
23+
pub fn malloc();
24+
pub fn realloc();
25+
pub fn free();
26+
pub fn exit();
27+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// This test checks the runtime symbols lint with the Unix symbols.
2+
3+
//@ only-unix
4+
//@ edition: 2021
5+
//@ normalize-stderr: "\*const [iu]8" -> "*const U8"
6+
7+
#![feature(c_variadic)]
8+
#![allow(clashing_extern_declarations)] // we are voluntarily testing different definitions
9+
10+
use core::ffi::{c_char, c_int, c_void};
11+
12+
fn invalid() {
13+
#[no_mangle]
14+
pub fn open() {}
15+
//~^ ERROR invalid definition of the runtime `open` symbol
16+
17+
extern "C" {
18+
pub fn read();
19+
//~^ ERROR invalid definition of the runtime `read` symbol
20+
21+
pub fn write();
22+
//~^ ERROR invalid definition of the runtime `write` symbol
23+
}
24+
25+
#[no_mangle]
26+
pub static close: () = ();
27+
//~^ ERROR invalid definition of the runtime `close` symbol
28+
29+
extern "C" {
30+
pub fn malloc();
31+
//~^ ERROR invalid definition of the runtime `malloc` symbol
32+
33+
pub fn realloc();
34+
//~^ ERROR invalid definition of the runtime `realloc` symbol
35+
36+
pub fn free();
37+
//~^ ERROR invalid definition of the runtime `free` symbol
38+
39+
pub fn exit();
40+
//~^ ERROR invalid definition of the runtime `exit` symbol
41+
}
42+
}
43+
44+
fn suspicious() {
45+
extern "C" {
46+
pub fn open(path: *const u8, oflag: usize, ...) -> c_int;
47+
//~^ WARN suspicious definition of the runtime `open` symbol
48+
49+
pub fn free(ptr: *const u8);
50+
//~^ WARN suspicious definition of the runtime `free` symbol
51+
52+
pub fn exit(code: f32) -> !;
53+
//~^ WARN suspicious definition of the runtime `exit` symbol
54+
}
55+
}
56+
57+
fn main() {}

0 commit comments

Comments
 (0)