[PATCH rust-next v2] rust: fmt: rework pointer formatting tests

Ke Sun via B4 Relay posted 1 patch 1 month, 2 weeks ago
rust/kernel/fmt.rs | 98 ++++++++++++++++++++----------------------------------
1 file changed, 36 insertions(+), 62 deletions(-)
[PATCH rust-next v2] rust: fmt: rework pointer formatting tests
Posted by Ke Sun via B4 Relay 1 month, 2 weeks ago
From: Ke Sun <sunke@kylinos.cn>

`test_ptr_formatting` depended on the `no_hash_pointers` setting and
skipped the remaining checks when the CRNG was not ready. Assert the
formatted variants against the plain `{:p}` output instead, and cover
the placeholder path.

Signed-off-by: Ke Sun <sunke@kylinos.cn>
---
This is a follow-up to the applied v15 series "rust: Add safe pointer
formatting support" (on rust-next), addressing the review feedback on
the KUnit tests.
---
Changes in v2:
- Fix the KUnit failure when the CRNG is not ready: `%p` emits the
  placeholder at a fixed length, ignoring width and zero-padding.
- Link to v1: https://lore.kernel.org/r/20260815-b4-hashedptr-followup-v1-1-83324702b4c9@kylinos.cn
---
 rust/kernel/fmt.rs | 98 ++++++++++++++++++++----------------------------------
 1 file changed, 36 insertions(+), 62 deletions(-)

diff --git a/rust/kernel/fmt.rs b/rust/kernel/fmt.rs
index 29582b053ab1f..cbdca7183d54b 100644
--- a/rust/kernel/fmt.rs
+++ b/rust/kernel/fmt.rs
@@ -215,83 +215,57 @@ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
 #[macros::kunit_tests(rust_kernel_fmt)]
 mod tests {
     use crate::{
-        bindings,
         prelude::fmt,
         str::CString, //
     };
 
+    // Placeholder used when the CRNG is not ready.
     #[cfg(CONFIG_64BIT)]
-    mod expected {
-        pub(super) const PTR_VALUE: usize = 0xffffffffdeadbeef;
-        pub(super) const PTR_VAL_NO_CRNG: &str = "(____ptrval____)";
-        pub(super) const HASHED_PREFIX: &str = "0x00000000";
-        pub(super) const RAW_POINTER: &str = "0xffffffffdeadbeef";
-        pub(super) const PADDED_RIGHT: &str = "      0xffffffffdeadbeef";
-        pub(super) const ZERO_PADDED: &str = "0x000000ffffffffdeadbeef";
-        pub(super) const HASHED_PADDED_RIGHT_PREFIX: &str = "      ";
-        pub(super) const HASHED_ZERO_PADDED_PREFIX: &str = "0x00000000000000";
-        pub(super) const CLAMPED: &str = "0x0000000000000ffffffffdeadbeef";
-    }
+    const PTR_VAL_NO_CRNG: &str = "(____ptrval____)";
 
     #[cfg(not(CONFIG_64BIT))]
-    mod expected {
-        pub(super) const PTR_VALUE: usize = 0xdeadbeef;
-        pub(super) const PTR_VAL_NO_CRNG: &str = "(ptrval)";
-        pub(super) const HASHED_PREFIX: &str = "0x";
-        pub(super) const RAW_POINTER: &str = "0xdeadbeef";
-        pub(super) const PADDED_RIGHT: &str = "              0xdeadbeef";
-        pub(super) const ZERO_PADDED: &str = "0x00000000000000deadbeef";
-        pub(super) const HASHED_PADDED_RIGHT_PREFIX: &str = "              ";
-        pub(super) const HASHED_ZERO_PADDED_PREFIX: &str = "0x00000000000000";
-        pub(super) const CLAMPED: &str = "0x0000000000000000000000deadbeef";
-    }
+    const PTR_VAL_NO_CRNG: &str = "(ptrval)";
+
+    #[cfg(CONFIG_64BIT)]
+    const PTR_VALUE: usize = 0xffffffffdeadbeef;
+
+    #[cfg(not(CONFIG_64BIT))]
+    const PTR_VALUE: usize = 0xdeadbeef;
 
     #[test]
     fn test_ptr_formatting() -> core::result::Result<(), crate::error::Error> {
-        let ptr: *const u8 = core::ptr::without_provenance(expected::PTR_VALUE);
+        let ptr: *const u8 = core::ptr::without_provenance(PTR_VALUE);
 
-        // SAFETY: `no_hash_pointers` is a global variable that is never concurrently modified —
-        // KUnit tests may run at boot (before `mark_readonly()`) or manually afterwards (when the
-        // variable is read-only). Reading is always safe.
-        let no_hash = unsafe { bindings::no_hash_pointers };
+        let cstr = CString::try_from_fmt(fmt!("{:p}", ptr))?;
+        let formatted = cstr.to_str()?;
 
-        if no_hash {
-            let cstr = CString::try_from_fmt(fmt!("{:p}", ptr))?;
-            assert_eq!(cstr.to_str()?, expected::RAW_POINTER);
+        // If the CRNG is not ready yet, `%p` emits the placeholder at a fixed
+        // length: `f.pad` still applies, zero-padding does not (see `ptr_to_id()`).
+        let (crng_ready, expected_suffix) = if let Some(suffix) = formatted.strip_prefix("0x") {
+            (true, suffix)
+        } else {
+            (false, formatted)
+        };
+        let (zero_padded_len, clamped_len) = if crng_ready {
+            (24, 31)
+        } else {
+            (PTR_VAL_NO_CRNG.len(), PTR_VAL_NO_CRNG.len())
+        };
 
-            let cstr = CString::try_from_fmt(fmt!("{:>24p}", ptr))?;
-            assert_eq!(cstr.to_str()?, expected::PADDED_RIGHT);
+        let cstr = CString::try_from_fmt(fmt!("{:>24p}", ptr))?;
+        let padded = cstr.to_str()?;
+        assert!(padded.ends_with(expected_suffix));
+        assert_eq!(padded.len(), 24);
 
-            let cstr = CString::try_from_fmt(fmt!("{:024p}", ptr))?;
-            assert_eq!(cstr.to_str()?, expected::ZERO_PADDED);
+        let cstr = CString::try_from_fmt(fmt!("{:024p}", ptr))?;
+        let zero_padded = cstr.to_str()?;
+        assert!(zero_padded.ends_with(expected_suffix));
+        assert_eq!(zero_padded.len(), zero_padded_len);
 
-            let cstr = CString::try_from_fmt(fmt!("{:0100p}", ptr))?;
-            assert_eq!(cstr.to_str()?, expected::CLAMPED);
-        } else {
-            let cstr = CString::try_from_fmt(fmt!("{:p}", ptr))?;
-            let formatted = cstr.to_str()?;
-            // If the RNG is not yet ready, `%p` falls back to a placeholder.
-            if formatted == expected::PTR_VAL_NO_CRNG {
-                return Ok(());
-            }
-            assert!(formatted.starts_with(expected::HASHED_PREFIX));
-            assert_ne!(formatted, expected::RAW_POINTER);
-
-            let cstr = CString::try_from_fmt(fmt!("{:>24p}", ptr))?;
-            assert!(cstr
-                .to_str()?
-                .starts_with(expected::HASHED_PADDED_RIGHT_PREFIX));
-
-            let cstr = CString::try_from_fmt(fmt!("{:024p}", ptr))?;
-            assert!(cstr
-                .to_str()?
-                .starts_with(expected::HASHED_ZERO_PADDED_PREFIX));
-
-            let cstr = CString::try_from_fmt(fmt!("{:0100p}", ptr))?;
-            let output = cstr.to_str()?;
-            assert!(output.starts_with("0x"));
-            assert!(!output[2..].chars().all(|c| c == '0'));
-        }
+        let cstr = CString::try_from_fmt(fmt!("{:0100p}", ptr))?;
+        let clamped = cstr.to_str()?;
+        assert!(clamped.ends_with(expected_suffix));
+        assert_eq!(clamped.len(), clamped_len);
 
         Ok(())
     }

---
base-commit: be387b625933ee12ed230b1c2af5e14f946c3040
change-id: 20260814-b4-hashedptr-followup-27a4d737f377

Best regards,
-- 
Ke Sun <sunke@kylinos.cn>