Rust for Linux List
 help / color / mirror / Atom feed
* [PATCH v1] rust: compiler_builtins: Fix silent trap in prohibited intrinsics
@ 2026-10-02  1:47 FUJITA Tomonori
  2026-10-02 10:06 ` Gary Guo
  0 siblings, 1 reply; 2+ messages in thread
From: FUJITA Tomonori @ 2026-10-02  1:47 UTC (permalink / raw)
  To: ojeda
  Cc: a.hindborg, acourbot, aliceryhl, bjorn3_gh, boqun, dakr,
	daniel.almeida, gary, lossin, tamird, tmgross, work,
	rust-for-linux, FUJITA Tomonori

From: FUJITA Tomonori <fujita.tomonori@gmail.com>

When core calls one of the stubs for builtins that should not be used,
the stub runs a trap instruction that prints no message, and the Oops
shows a wrong name. For example, when __rust__udivti3() is called on
x86_64, the Oops shows:

  Oops: invalid opcode: 0000 [#1] SMP
  RIP: 0010:__rust__adddf3+0x0/0x10

The stubs call panic!(), but since Rust 1.79, rustc does not allow code
in a `#![compiler_builtins]` crate to link to functions in other crates,
and it silently turns such calls that do not return into a trap [1]. In
addition, all the stubs have the same code, so LLVM merges them into one
function.

Replace panic!() with _printk() and BUG(), as the panic handler in the
kernel crate does. These are C functions, and rustc allows calls to
them. Each stub passes its own name to _printk(), so the stubs are no
longer merged:

  __udivti3 called: `u128` should not be used
  kernel BUG at rust/helpers/bug.c:7!

Link: https://github.com/rust-lang/rust/pull/122580 [1]
Assisted-by: LLM
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
Another option to fix this is moving the stubs to a normal crate (not
`#![compiler_builtins]`), so that panic!() works as usual.
---
 rust/compiler_builtins.rs | 39 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 3 deletions(-)

diff --git a/rust/compiler_builtins.rs b/rust/compiler_builtins.rs
index fc6b54636dd5..9416ca4c23f5 100644
--- a/rust/compiler_builtins.rs
+++ b/rust/compiler_builtins.rs
@@ -9,8 +9,8 @@
 //! At the moment, some builtins are required that should not be. For instance,
 //! [`core`] has 128-bit integers functionality which we should not be compiling
 //! in. We will work with upstream [`core`] to provide feature flags to disable
-//! the parts we do not need. For the moment, we define them to [`panic!`] at
-//! runtime for simplicity to catch mistakes, instead of performing surgery
+//! the parts we do not need. For the moment, we define them to print an error
+//! and call `BUG()` at runtime to catch mistakes, instead of performing surgery
 //! on `core.o`.
 //!
 //! In any case, all these symbols are weakened to ensure we do not override
@@ -25,13 +25,46 @@
 #![no_builtins]
 #![no_std]
 
+unsafe extern "C" {
+    #[cfg(CONFIG_PRINTK)]
+    fn _printk(fmt: *const u8, ...) -> core::ffi::c_int;
+    fn rust_helper_BUG() -> !;
+}
+
+// In a `#![compiler_builtins]` crate, code cannot link to functions in other
+// crates. `rustc` rejects such calls, except that it silently turns the ones
+// that do not return (e.g. `panic!`) into a trap.
+#[cold]
+#[inline(never)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+fn intrinsic_called(name: &str, reason: &str) -> ! {
+    #[cfg(CONFIG_PRINTK)]
+    // SAFETY: The format string is NUL-terminated. Each `%.*s` takes a
+    // `c_int` length and a pointer. `name.as_ptr()` is valid for reads of
+    // `name.len()` bytes, and so is `reason.as_ptr()` for `reason.len()`
+    // bytes.
+    unsafe {
+        _printk(
+            // "\x010" is `KERN_EMERG`.
+            c"\x010%.*s called: %.*s\n".to_bytes_with_nul().as_ptr(),
+            name.len() as core::ffi::c_int,
+            name.as_ptr(),
+            reason.len() as core::ffi::c_int,
+            reason.as_ptr(),
+        )
+    };
+
+    // SAFETY: FFI call.
+    unsafe { rust_helper_BUG() }
+}
+
 macro_rules! define_panicking_intrinsics(
     ($reason: tt, { $($ident: ident, )* }) => {
         $(
             #[doc(hidden)]
             #[export_name = concat!("__rust", stringify!($ident))]
             pub extern "C" fn $ident() {
-                panic!($reason);
+                intrinsic_called(stringify!($ident), $reason)
             }
         )*
     }

base-commit: c82c75ae11fae66cf070562f9b5241a4663f30cb
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH v1] rust: compiler_builtins: Fix silent trap in prohibited intrinsics
  2026-10-02  1:47 [PATCH v1] rust: compiler_builtins: Fix silent trap in prohibited intrinsics FUJITA Tomonori
@ 2026-10-02 10:06 ` Gary Guo
  0 siblings, 0 replies; 2+ messages in thread
From: Gary Guo @ 2026-10-02 10:06 UTC (permalink / raw)
  To: FUJITA Tomonori, ojeda
  Cc: a.hindborg, acourbot, aliceryhl, bjorn3_gh, boqun, dakr,
	daniel.almeida, gary, lossin, tamird, tmgross, work,
	rust-for-linux, FUJITA Tomonori

On Fri Oct 2, 2026 at 2:47 AM BST, FUJITA Tomonori wrote:
> From: FUJITA Tomonori <fujita.tomonori@gmail.com>
>
> When core calls one of the stubs for builtins that should not be used,
> the stub runs a trap instruction that prints no message, and the Oops
> shows a wrong name. For example, when __rust__udivti3() is called on
> x86_64, the Oops shows:
>
>   Oops: invalid opcode: 0000 [#1] SMP
>   RIP: 0010:__rust__adddf3+0x0/0x10
>
> The stubs call panic!(), but since Rust 1.79, rustc does not allow code
> in a `#![compiler_builtins]` crate to link to functions in other crates,
> and it silently turns such calls that do not return into a trap [1]. In
> addition, all the stubs have the same code, so LLVM merges them into one
> function.
>
> Replace panic!() with _printk() and BUG(), as the panic handler in the
> kernel crate does. These are C functions, and rustc allows calls to
> them. Each stub passes its own name to _printk(), so the stubs are no
> longer merged:
>
>   __udivti3 called: `u128` should not be used
>   kernel BUG at rust/helpers/bug.c:7!
>
> Link: https://github.com/rust-lang/rust/pull/122580 [1]
> Assisted-by: LLM
> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> ---
> Another option to fix this is moving the stubs to a normal crate (not
> `#![compiler_builtins]`), so that panic!() works as usual.

I think we should do this.

Best,
Gary

> ---
>  rust/compiler_builtins.rs | 39 ++++++++++++++++++++++++++++++++++++---
>  1 file changed, 36 insertions(+), 3 deletions(-)
>
> diff --git a/rust/compiler_builtins.rs b/rust/compiler_builtins.rs
> index fc6b54636dd5..9416ca4c23f5 100644
> --- a/rust/compiler_builtins.rs
> +++ b/rust/compiler_builtins.rs
> @@ -9,8 +9,8 @@
>  //! At the moment, some builtins are required that should not be. For instance,
>  //! [`core`] has 128-bit integers functionality which we should not be compiling
>  //! in. We will work with upstream [`core`] to provide feature flags to disable
> -//! the parts we do not need. For the moment, we define them to [`panic!`] at
> -//! runtime for simplicity to catch mistakes, instead of performing surgery
> +//! the parts we do not need. For the moment, we define them to print an error
> +//! and call `BUG()` at runtime to catch mistakes, instead of performing surgery
>  //! on `core.o`.
>  //!
>  //! In any case, all these symbols are weakened to ensure we do not override
> @@ -25,13 +25,46 @@
>  #![no_builtins]
>  #![no_std]
>  
> +unsafe extern "C" {
> +    #[cfg(CONFIG_PRINTK)]
> +    fn _printk(fmt: *const u8, ...) -> core::ffi::c_int;
> +    fn rust_helper_BUG() -> !;
> +}
> +
> +// In a `#![compiler_builtins]` crate, code cannot link to functions in other
> +// crates. `rustc` rejects such calls, except that it silently turns the ones
> +// that do not return (e.g. `panic!`) into a trap.
> +#[cold]
> +#[inline(never)]
> +#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
> +fn intrinsic_called(name: &str, reason: &str) -> ! {
> +    #[cfg(CONFIG_PRINTK)]
> +    // SAFETY: The format string is NUL-terminated. Each `%.*s` takes a
> +    // `c_int` length and a pointer. `name.as_ptr()` is valid for reads of
> +    // `name.len()` bytes, and so is `reason.as_ptr()` for `reason.len()`
> +    // bytes.
> +    unsafe {
> +        _printk(
> +            // "\x010" is `KERN_EMERG`.
> +            c"\x010%.*s called: %.*s\n".to_bytes_with_nul().as_ptr(),
> +            name.len() as core::ffi::c_int,
> +            name.as_ptr(),
> +            reason.len() as core::ffi::c_int,
> +            reason.as_ptr(),
> +        )
> +    };
> +
> +    // SAFETY: FFI call.
> +    unsafe { rust_helper_BUG() }
> +}
> +
>  macro_rules! define_panicking_intrinsics(
>      ($reason: tt, { $($ident: ident, )* }) => {
>          $(
>              #[doc(hidden)]
>              #[export_name = concat!("__rust", stringify!($ident))]
>              pub extern "C" fn $ident() {
> -                panic!($reason);
> +                intrinsic_called(stringify!($ident), $reason)
>              }
>          )*
>      }
>
> base-commit: c82c75ae11fae66cf070562f9b5241a4663f30cb



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-02 10:06 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-02  1:47 [PATCH v1] rust: compiler_builtins: Fix silent trap in prohibited intrinsics FUJITA Tomonori
2026-10-02 10:06 ` Gary Guo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox