[PATCH 2/2] rust: str: parse_int: accept a trailing newline like kstrtol()
From: Younes Akhouayri via B4 Relay
Date: Tue Oct 27 2026 - 08:18:48 EST
From: Younes Akhouayri <git@xxxxxxxxx>
The documentation of `ParseInt` says that any string parsed by
`kstrtol()` or `kstrtoul()` is also parsed by `from_str()`. However,
those functions accept a single trailing newline, and `from_str()` does
not:
kstrtoint("5\n", 0, &v) == 0, v == 5
i32::from_str("5\n") == Err(EINVAL)
A trailing newline is common when the string comes from user space, for
example when a value is written to a sysfs file with `echo`.
Fix it by removing a single trailing newline before parsing, and add
doctests for it.
Fixes: 51d9ee90ea90 ("rust: str: add radix prefixed integer parsing functions")
Signed-off-by: Younes Akhouayri <git@xxxxxxxxx>
---
rust/kernel/str/parse_int.rs | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/str/parse_int.rs b/rust/kernel/str/parse_int.rs
index 07e1fbd7be8f..ada355306fc5 100644
--- a/rust/kernel/str/parse_int.rs
+++ b/rust/kernel/str/parse_int.rs
@@ -54,8 +54,8 @@ fn strip_radix(src: &BStr) -> Result<(u32, &BStr)> {
/// Strings beginning with `0x`, `0o`, or `0b` are parsed as hex, octal, or
/// binary respectively. Strings beginning with `0` otherwise are parsed as
/// octal. Anything else is parsed as decimal. A leading `+` or `-` is also
-/// permitted. Any string parsed by [`kstrtol()`] or [`kstrtoul()`] will be
-/// successfully parsed.
+/// permitted, as is a single trailing newline. Any string parsed by
+/// [`kstrtol()`] or [`kstrtoul()`] will be successfully parsed.
///
/// [`kstrtol()`]: https://docs.kernel.org/core-api/kernel-api.html#c.kstrtol
/// [`kstrtoul()`]: https://docs.kernel.org/core-api/kernel-api.html#c.kstrtoul
@@ -88,11 +88,15 @@ fn strip_radix(src: &BStr) -> Result<(u32, &BStr)> {
/// assert!(i32::from_str(b_str!("0x-5")).is_err());
/// assert!(i32::from_str(b_str!("0x+5")).is_err());
/// assert!(i32::from_str(b_str!("-+5")).is_err());
+///
+/// assert_eq!(Ok(5u8), u8::from_str(b_str!("5\n")));
+/// assert!(u8::from_str(b_str!("5\n\n")).is_err());
/// ```
pub trait ParseInt: private::FromStrRadix + TryFrom<u64> {
/// Parse a string according to the description in [`Self`].
fn from_str(src: &BStr) -> Result<Self> {
- match src.deref() {
+ let src = src.strip_suffix(b"\n").unwrap_or(src);
+ match src {
[b'-', rest @ ..] => {
let (radix, digits) = strip_radix(rest.as_ref())?;
// 2's complement values range from -2^(b-1) to 2^(b-1)-1.
--
2.56.0