Skip to content

Add lint againts invalid runtime symbol definitions#155521

Open
Urgau wants to merge 8 commits into
rust-lang:mainfrom
Urgau:runtime-symbols
Open

Add lint againts invalid runtime symbol definitions#155521
Urgau wants to merge 8 commits into
rust-lang:mainfrom
Urgau:runtime-symbols

Conversation

@Urgau
Copy link
Copy Markdown
Member

@Urgau Urgau commented Apr 19, 2026

View all comments

This PR adds a deny-by-default lint againts invalid runtime symbol definitions, those runtime symbols are assumed and used by core1 and rustc with a specific definition.

We have had multiple reports of users tripping over std symbols (addressed in a future PR):

This PR is a second attempt after #146505, where T-lang had some reservations about a blanket lint that does not check the signature, which is now done with this PR, and about linting of std runtime symbols when std is not linked, which this PR omits by not including any std runtime symbols (for now).

invalid_runtime_symbol_definitions

(deny-by-default)

The invalid_runtime_symbol_definitions lint checks the signature of items whose symbol name is a runtime symbols expected by core.

Example

#[unsafe(no_mangle)]
pub fn memcmp() {} // invalid definition of the `memcmp` runtime symbol
error: invalid definition of the runtime `memcmp` symbol used by the standard library
 --> a.rs:2:1
  |
4 | fn memcmp() {}
  | ^^^^^^^^^^^
  |
  = note: expected `unsafe extern "C" fn(*const c_void, *const c_void, usize) -> i32`
          found    `fn()`
  = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "memcmp")]`, or `#[link_name = "memcmp"]`
  = note: `#[deny(invalid_runtime_symbol_definitions)]` on by default

Explanation

Up-most care is required when defining runtime symbols assumed and used by the standard library. They must follow the C specification, not use any standard-library facility or undefined behavior may occur.

The symbols currently checked are memcpy, memmove, memset, memcmp, bcmp and strlen.

@rustbot labels +I-lang-nominated +T-lang +needs-fcp +A-lints
cc @rust-lang/lang-ops
r? compiler

Footnotes

  1. https://doc.rust-lang.org/core/index.html#how-to-use-the-core-library

@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 19, 2026

These commits modify the Cargo.lock file. Unintentional changes to Cargo.lock can be introduced when switching branches and rebasing PRs.

If this was unintentional then you should revert the changes before this PR is merged.
Otherwise, you can ignore this comment.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Apr 19, 2026
@rustbot rustbot added A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. I-lang-nominated Nominated for discussion during a lang team meeting. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. T-lang Relevant to the language team labels Apr 19, 2026
@rust-log-analyzer

This comment has been minimized.

@Urgau Urgau force-pushed the runtime-symbols branch from 46b7db0 to d81044c Compare April 19, 2026 16:26
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@Urgau Urgau force-pushed the runtime-symbols branch from 4debba0 to 058c0e4 Compare April 19, 2026 19:43
@rust-log-analyzer

This comment has been minimized.

///
/// ### Explanation
///
/// Up-most care is required when defining runtime symbols assumed and
Copy link
Copy Markdown
Contributor

@PatchMixolydic PatchMixolydic Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:

Suggested change
/// Up-most care is required when defining runtime symbols assumed and
/// Utmost care is required when defining runtime symbols assumed and

View changes since the review

@rust-log-analyzer

This comment has been minimized.

@traviscross traviscross added the P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang label Apr 19, 2026
@rust-log-analyzer

This comment has been minimized.

@Urgau Urgau force-pushed the runtime-symbols branch from 1b7638a to ed313a0 Compare April 20, 2026 06:11
@rust-log-analyzer

This comment has been minimized.

@Urgau Urgau force-pushed the runtime-symbols branch from ed313a0 to 0e3b44e Compare April 20, 2026 06:51
@rustbot

This comment has been minimized.

@traviscross
Copy link
Copy Markdown
Contributor

Thanks @Urgau for adjusting based on the feedback and moving this forward.

@rfcbot fcp merge lang

@traviscross traviscross added the I-lang-radar Items that are on lang's radar and will need eventual work or consideration. label Apr 22, 2026
@traviscross

This comment was marked as duplicate.

@jackh726
Copy link
Copy Markdown
Member

jackh726 commented Apr 22, 2026

Should this also include rust_eh_personality?

@steffahn
Copy link
Copy Markdown
Member

As far as I understood the lang meeting discussion, there was no concern with this PR.

But some opinion that it doesn’t fully replace the previous PR, since some warn-by-default lint more generally applicable (and to actually address the user reports, which were about open and read) might also be desirable. All of this can of course be follow-up work so it shouldn’t block us from getting the lint as in this PR; but it’s be useful to clarify that the user reports (currently mentioned in the OP of this PR) aren’t addressed yet with this PR merged, and in this regard this isn’t a full replacement of #146505.

@scottmcm
Copy link
Copy Markdown
Member

My interpretation here: this lint is valuable because the wrong signature for something on the well-known list is clearly and always wrong, so deny makes sense. We should have this lint. (And I'm find expanding to more functions so long as they meet that "definitely incontrovertibly wrong signature for that name that rustc or one of your linked libraries uses" bar. I don't know if we include extern function declarations in rlibs, but if this expanded to a general check that you're not conflicting with other rust libraries that'd also be cool -- not this PR I assume, though.)

Another lint, for "it's very suspicious that you're defining an unmangled open" kinds of things probably also makes sense. That might not be deny though, since it's not as unquestionably wrong. It's a rare case of a rustc lint where I'm plausibly fine with the only mitigation being to allow it, since you could just crate-level-allow it for those very few crates where doing this is intentional because it's trying to implement such things. (Notably if you're trying to define a memcpy you'll need to do extra steps already anyway, IIRC.) But that wouldn't be this PR.

@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors Bot commented May 25, 2026

☀️ Try build successful (CI)
Build commit: 110eb49 (110eb4964d2acf5f5faee793d0d7783e28daa80a, parent: 6083f7891b5088184968e050d0eaecc7bcfd2b3d)

@nbdd0121
Copy link
Copy Markdown
Member

nbdd0121 commented May 25, 2026

It's explicitly only blessed for Rust-to-Rust calls. The rules do not apply to e.g. calling libc. Furthermore, we're discussing relaxing this.

Many of the code samples in the search that I quoted https://github.com/search?q=language%3Arust+fn+memcpy&type=code are Rust-to-Rust calls as memcpy is defined in Rust.

I still don't think the u8/i8 case is something the lint should accept. Other than reference to raw pointer of the same mutability, I don't think we should accept any divergence.

Many of these programs also probably don't care about CFI (or only have direct function call emitted for these functions, which will be the case for LLVM-generated calls to those functions), and as this is a deny-by-default lint, I think rejecting these working code is excessive. I wouldn't be concerned if the lint is only warn-by-default.

@joshtriplett
Copy link
Copy Markdown
Member

joshtriplett commented Jun 3, 2026

@Darksonn wrote:

I still don't think the u8/i8 case is something the lint should accept. Other than reference to raw pointer of the same mutability, I don't think we should accept any divergence.

AFAICT, the point of this lint is "you're defining a conflicting symbol that couldn't possibly work. If you're defining something that uses a pointer but it's a different signedness, or for that matter something that accepts an Option<NonNull>, then that is something that could work. I think we should be making a best-effort here, to catch cases where someone might have defined their own function without even realizing it was a conflict; we're not trying to stop people who are reasonably trying to write an interposing symbol.

Could you elaborate on why you feel it's a problem for us to suppress the lint if the only mismatch is *mut i8 vs *mut u8 or similar?

Is CFI an issue here? Would those types be considered incompatible, tripping a CFI fault if called?

@scottmcm
Copy link
Copy Markdown
Member

scottmcm commented Jun 3, 2026

From my perspective, I would absolutely expect ABI-compatible being fine here.

If we had this check on posix_memalign, for example, I'd want to be able to use mem::Alignment as the parameter type for the alignment. Insisting that it can only be a type alias for usize would make me sad, since it would keep me from encoding preconditions in the types.

@RalfJung
Copy link
Copy Markdown
Member

RalfJung commented Jun 3, 2026

Is CFI an issue here? Would those types be considered incompatible, tripping a CFI fault if called?

Yes. That's exactly the point. That's why I referenced rust-lang/unsafe-code-guidelines#489 above.

The plan to make Rust CFI-compatible is to declare some calls that we currently deem ABI-compatible to instead have EB (Erroneous Behavior), together with a promise that Rust in its default configuration will not act on this EB. And among the calls that we'll have to make EB is a *mut u8 vs *mut i8 mismatch (or really any *mut T vs *mut U with different pointee types).

@joshtriplett
Copy link
Copy Markdown
Member

@RalfJung I see. That makes sense.

Still not certain if we should be linting such mismatches yet, given that this is a best-effort lint, but given the CFI concern, it seems reasonable to ship this lint without the mismatch handling.

@traviscross traviscross removed I-lang-nominated Nominated for discussion during a lang team meeting. P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang labels Jun 3, 2026
@Urgau Urgau force-pushed the runtime-symbols branch from 57e3c83 to dd136e7 Compare June 4, 2026 18:17
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Jun 4, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Urgau
Copy link
Copy Markdown
Member Author

Urgau commented Jun 4, 2026

Given the discussion above, the T-lang triage notes and the Zulip thread. I've removed the type normalization/mismatch handling and gone back to exact type equality.

@ojeda @nbdd0121 could I ask you to prepare a patch that allow the lint (#[allow(invalid_runtime_symbol_definitions)]), so I can unblock CI and land the lint.

@ojeda
Copy link
Copy Markdown
Contributor

ojeda commented Jun 4, 2026

Thanks, I can do that.

@tmandry
Copy link
Copy Markdown
Member

tmandry commented Jun 5, 2026

If we had this check on posix_memalign, for example, I'd want to be able to use mem::Alignment as the parameter type for the alignment. Insisting that it can only be a type alias for usize would make me sad, since it would keep me from encoding preconditions in the types.

There's something I don't understand here. I don't think you would use mem::Alignment in the exported extern "C" definition of posix_memalign, because you don't necessarily control all callers. Similar for NonNull. What you might want instead is a second, safe(-r) function to expose to Rust code with stronger types, and have one call the other.


With that said, I believe this is the first time we're going to lint over this new category of Erroneous Behavior to satisfy CFI, and CFI is rather strict, and deny-by-default is rather strong. If there is a convincing case where this lint would steer people away from using safer types, I'd want to discuss more with the team before this lands.

I'm going to renominate so this stays on our radar, but we may be able to resolve it async if we agree there are no examples of this.

@rustbot label I-lang-nominated

@rustbot rustbot added the I-lang-nominated Nominated for discussion during a lang team meeting. label Jun 5, 2026
@traviscross traviscross added the P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang label Jun 5, 2026
ojeda added a commit to Rust-for-Linux/linux that referenced this pull request Jun 5, 2026
Starting with Rust 1.98.0 (expected 2026-08-20), Rust is introducing
a new deny-by-default lint which checks the signature of items whose
symbol name is a runtime symbol expected by `core`:

    error: invalid definition of the runtime `strlen` symbol used by the standard library
         --> rust/uapi/uapi_generated.rs:13998:5
          |
    13998 |     pub fn strlen(s: *const ffi::c_char) -> usize;
          |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
          |
          = note: expected `unsafe extern "C" fn(*const i8) -> usize`
                  found    `unsafe extern "C" fn(*const u8) -> usize`
          = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "strlen")]`, or `#[link_name = "strlen"]`
          = note: `#[deny(invalid_runtime_symbol_definitions)]` on by default

    error: invalid definition of the runtime `strlen` symbol used by the standard library
         --> rust/bindings/bindings_generated.rs:19877:5
          |
    19877 |     pub fn strlen(s: *const ffi::c_char) -> usize;
          |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
          |
          = note: expected `unsafe extern "C" fn(*const i8) -> usize`
                  found    `unsafe extern "C" fn(*const u8) -> usize`
          = help: either fix the signature or remove any attributes like `#[unsafe(no_mangle)]`, `#[unsafe(export_name = "strlen")]`, or `#[link_name = "strlen"]`
          = note: `#[deny(invalid_runtime_symbol_definitions)]` on by default

Thus `allow` the lint in `bindings` and `uapi`.

Link: rust-lang/rust#155521 [1]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Comment thread compiler/rustc_lint/src/runtime_symbols.rs Outdated
@ojeda
Copy link
Copy Markdown
Contributor

ojeda commented Jun 5, 2026

Please cherry-pick ojeda@422215a (will conflict with #157151).

I am allowing the lint in that commit, but for the actual kernel patch I am considering just blocking the set of functions in bindgen's generation to keep the lint enabled -- so far it is just strlen and we don't call it.

Urgau and others added 6 commits June 5, 2026 18:53
@Urgau Urgau force-pushed the runtime-symbols branch from dd136e7 to 56403c1 Compare June 5, 2026 16:54
@Urgau
Copy link
Copy Markdown
Member Author

Urgau commented Jun 5, 2026

Thanks. I've cherry-picked the patch.

Let's verify that it works as expected.
@bors try jobs=x86_64-rust-for-linux

@rust-bors

This comment has been minimized.

@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors Bot commented Jun 5, 2026

☀️ Try build successful (CI)
Build commit: d3bea8c (d3bea8c7f040459e99f8e5ef8ac913f53dbb3ba9, parent: ac6f3a3e778a586854bdbf8f15202e11e2348d9f)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CI Area: Our Github Actions CI A-compiler-builtins Area: compiler-builtins (https://github.com/rust-lang/compiler-builtins) A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. A-rust-for-linux Relevant for the Rust-for-Linux project A-testsuite Area: The testsuite used to check the correctness of rustc disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. I-lang-nominated Nominated for discussion during a lang team meeting. I-lang-radar Items that are on lang's radar and will need eventual work or consideration. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-infra Relevant to the infrastructure team, which will review and decide on the PR/issue. T-lang Relevant to the language team T-libs Relevant to the library team, which will review and decide on the PR/issue. to-announce Announce this issue on triage meeting

Projects

None yet

Development

Successfully merging this pull request may close these issues.