* [PATCH v2] rust: time: make Delta division and remainder fail consistently
@ 2026-10-01 4:29 ` chenhan
2026-10-01 8:10 ` Andreas Hindborg
2026-10-01 10:46 ` Miguel Ojeda
0 siblings, 2 replies; 5+ messages in thread
From: chenhan @ 2026-10-01 4:29 UTC (permalink / raw)
To: rust-for-linux
Cc: a.hindborg, boqun, fujita.tomonori, frederic, lyude, tglx,
anna-maria, jstultz, sboyd, ojeda, gary, bjorn3_gh, lossin,
aliceryhl, tmgross, dakr, daniel.almeida, tamird, acourbot, work,
miguel.ojeda.sandonis, tomo, georgeandrout13, linux-kernel,
stable
Delta's division and rem_nanos() use Rust operators on 64-bit and C
helpers on 32-bit. The report shows that rem_nanos(0) can return 10 for
a 10 ns dividend on ARMv7, while the same call panics on x86-64. The
i64::MIN / -1 case also differs, and neither API documents these inputs.
Use Rust's signed division and remainder semantics on both architectures,
as discussed in the report. Div should behave like i64 division, and
rem_nanos() supplies the corresponding remainder operation with a 32-bit
divisor. Both reject zero divisors and i64::MIN with -1, even when Rust
overflow checks are disabled.
Check these inputs before entering the architecture-specific code and
document the panic conditions. This preserves the API signatures and
valid-input results, but intentionally makes invalid inputs panic on
32-bit too. No in-tree callers of either API were found at the base
commit. Correct the rem_nanos() parameter name to divisor as well.
Tested on x86-64 and ARMv7 QEMU with a built-in Rust module that passes
runtime operands to both APIs. Separate boots verify each panic case;
valid-input tests cover mixed signs, signed extrema and full-width
division operands.
Fixes: 4521438fb076 ("rust: time: Implement basic arithmetic operations for Delta")
Reported-by: Georgios Androutsopoulos <georgeandrout13@gmail.com>
Closes: https://github.com/Rust-for-Linux/linux/issues/1254
Link: https://github.com/Rust-for-Linux/linux/issues/1254#issuecomment-5869573842
Link: https://github.com/Rust-for-Linux/linux/issues/1254#issuecomment-5869925737
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: chenhan <chenhan0017.work@gmail.com>
---
Changes in v2:
- Put the checks directly in div() and rem_nanos(), following Tomonori's
suggestion. Each proposed helper had only one caller, and no other
concrete users were found to justify a math module.
- Move # Panics onto div(), remove private-helper references, link the
integer types, and describe each API's input domain separately.
- Explain the arithmetic and pointer conditions in the SAFETY comments.
- Add Georgios' Reported-by and all M:/R: contacts requested by Miguel.
- Cite the issue discussion establishing the intended panic semantics.
- Replace the local CONFIG_SAMPLE_RUST_REPRO name with a description of
the test; the API calls and expected results are explained below.
- Base this revision on timekeeping-next at 2ea0119f72db, preserving the
new to_jiffies_timeout() method, and rerun x86-64/ARMv7 validation.
Caller audit: no calls to either API outside their definitions were found
on the base above or rust-next at c82c75ae11fa. This covered tracked Rust
sources, including drivers, samples and lib, using named-call searches
and inspection of division expressions in Delta/Instant users, including
elapsed() results. Time-unit conversions use fixed positive divisors;
to_jiffies_timeout() uses an unsigned multiply/add/divide helper;
num/bounded.rs operates on generic integer types. None provides a concrete
extra user for the proposed signed helpers.
I kept the stable Cc as suggested. The 32-bit invalid-input behavior does
change, and I have not identified an affected in-tree caller or audited
all stable branches. Please let me know if this consistency fix should
not be backported.
On the MIN / -1 safety question: div_s64_rem() computes a quotient even
though the caller discards it. V1 already checked this input before the C
call; v2 keeps the guard and makes the representable-quotient condition
explicit in the SAFETY comment. Rust's signed remainder operator panics
for this input even though the mathematical remainder would be zero.
Testing: CONFIG_SAMPLE_RUST_REPRO in v1 was a local Kconfig option for
samples/rust/rust_repro.rs; neither was included in that submission.
The built-in module read dividend: i64, divisor: i32 and an operation
selector from module parameters during init, then evaluated one of:
Delta::from_nanos(dividend) / Delta::from_nanos(i64::from(divisor))
Delta::from_nanos(dividend).rem_nanos(divisor).as_nanos()
For v2, an expanded module passes black_box operands to the actual Delta
APIs. Each architecture has a valid-input boot with 26 division and 21
remainder comparisons, and four separate boots for the panic cases.
The following core cases pass on both x86-64 and ARMv7:
dividend divisor division remainder (nanoseconds)
10 0 panic panic
i64::MIN -1 panic panic
10 3 3 1
Further valid cases include mixed signs, i32::MIN divisors,
i64::MIN/i64::MAX dividends and full-width i64 divisors for division.
Both configurations have CONFIG_RUST_OVERFLOW_CHECKS=y; I have not
boot-tested with it disabled. The added checks are unconditional.
For the identity question: chenhan is the identity I consistently use,
and chenhan0017.work@gmail.com is my email address. I also participate
in issue #1254 as WindDevil on GitHub.
rust/kernel/time.rs | 46 +++++++++++++++++++++++++++++++++++++--------
1 file changed, 38 insertions(+), 8 deletions(-)
diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
index 5ae377e70dd8..31a1c95bc786 100644
--- a/rust/kernel/time.rs
+++ b/rust/kernel/time.rs
@@ -412,8 +412,20 @@ fn mul_assign(&mut self, rhs: i64) {
impl ops::Div for Delta {
type Output = i64;
+ /// # Panics
+ ///
+ /// Panics if `rhs` is zero, or if `self` represents [`i64::MIN`] nanoseconds
+ /// and `rhs` represents `-1` nanosecond.
#[inline]
fn div(self, rhs: Self) -> Self::Output {
+ if rhs.value == 0 {
+ panic!("attempt to divide by zero");
+ }
+
+ if self.value == i64::MIN && rhs.value == -1 {
+ panic!("attempt to divide with overflow");
+ }
+
#[cfg(CONFIG_64BIT)]
{
self.value / rhs.value
@@ -421,7 +433,7 @@ fn div(self, rhs: Self) -> Self::Output {
#[cfg(not(CONFIG_64BIT))]
{
- // SAFETY: This function is always safe to call regardless of the input values
+ // SAFETY: The divisor is non-zero and the quotient is representable.
unsafe { bindings::div64_s64(self.value, rhs.value) }
}
}
@@ -614,16 +626,33 @@ pub fn to_jiffies_timeout(self) -> Delta<Jiffy> {
Delta::<Jiffy>::from_jiffies(jiffies)
}
- /// Return `self % dividend` where `dividend` is in nanoseconds.
+ /// Return `self % divisor`, where `divisor` is a number of nanoseconds.
+ ///
+ /// A non-zero result has the sign of `self`, and the magnitude of the result
+ /// is strictly smaller than that of `divisor`.
///
- /// The kernel doesn't have any emulation for `s64 % s64` on 32 bit platforms, so this is
- /// limited to 32 bit dividends.
+ /// The divisor is an [`i32`] because `div_s64_rem()`, used on 32-bit
+ /// platforms, takes a signed 32-bit divisor. The dividend remains an [`i64`].
+ ///
+ /// # Panics
+ ///
+ /// Panics if `divisor` is zero, or if `self` represents [`i64::MIN`]
+ /// nanoseconds and `divisor` is `-1`, matching Rust's signed remainder
+ /// operator even though the remainder would be zero.
#[inline]
- pub fn rem_nanos(self, dividend: i32) -> Self {
+ pub fn rem_nanos(self, divisor: i32) -> Self {
+ if divisor == 0 {
+ panic!("attempt to calculate the remainder with a divisor of zero");
+ }
+
+ if self.value == i64::MIN && divisor == -1 {
+ panic!("attempt to calculate the remainder with overflow");
+ }
+
#[cfg(CONFIG_64BIT)]
{
Self {
- value: self.as_nanos() % i64::from(dividend),
+ value: self.as_nanos() % i64::from(divisor),
}
}
@@ -631,8 +660,9 @@ pub fn rem_nanos(self, dividend: i32) -> Self {
{
let mut rem = 0;
- // SAFETY: `rem` is in the stack, so we can always provide a valid pointer to it.
- unsafe { bindings::div_s64_rem(self.as_nanos(), dividend, &mut rem) };
+ // SAFETY: The divisor is non-zero and the quotient is representable.
+ // `&mut rem` provides a valid, aligned pointer to a writable `i32` for this call.
+ unsafe { bindings::div_s64_rem(self.as_nanos(), divisor, &mut rem) };
Self {
value: i64::from(rem),
base-commit: 2ea0119f72dba597aa8a98cbdb72c564bfc5cb38
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] rust: time: make Delta division and remainder fail consistently
2026-10-01 4:29 ` [PATCH v2] rust: time: make Delta division and remainder fail consistently chenhan
@ 2026-10-01 8:10 ` Andreas Hindborg
2026-10-01 9:31 ` FUJITA Tomonori
2026-10-01 10:46 ` Miguel Ojeda
1 sibling, 1 reply; 5+ messages in thread
From: Andreas Hindborg @ 2026-10-01 8:10 UTC (permalink / raw)
To: chenhan, rust-for-linux
Cc: boqun, fujita.tomonori, frederic, lyude, tglx, anna-maria,
jstultz, sboyd, ojeda, gary, bjorn3_gh, lossin, aliceryhl,
tmgross, dakr, daniel.almeida, tamird, acourbot, work,
miguel.ojeda.sandonis, tomo, georgeandrout13, linux-kernel,
stable
"chenhan" <chenhan0017.work@gmail.com> writes:
> Delta's division and rem_nanos() use Rust operators on 64-bit and C
> helpers on 32-bit. The report shows that rem_nanos(0) can return 10 for
> a 10 ns dividend on ARMv7, while the same call panics on x86-64. The
> i64::MIN / -1 case also differs, and neither API documents these inputs.
>
> Use Rust's signed division and remainder semantics on both architectures,
> as discussed in the report. Div should behave like i64 division, and
> rem_nanos() supplies the corresponding remainder operation with a 32-bit
> divisor. Both reject zero divisors and i64::MIN with -1, even when Rust
> overflow checks are disabled.
>
> Check these inputs before entering the architecture-specific code and
> document the panic conditions. This preserves the API signatures and
> valid-input results, but intentionally makes invalid inputs panic on
> 32-bit too. No in-tree callers of either API were found at the base
> commit. Correct the rem_nanos() parameter name to divisor as well.
>
> Tested on x86-64 and ARMv7 QEMU with a built-in Rust module that passes
> runtime operands to both APIs. Separate boots verify each panic case;
> valid-input tests cover mixed signs, signed extrema and full-width
> division operands.
>
> Fixes: 4521438fb076 ("rust: time: Implement basic arithmetic operations for Delta")
> Reported-by: Georgios Androutsopoulos <georgeandrout13@gmail.com>
> Closes: https://github.com/Rust-for-Linux/linux/issues/1254
> Link: https://github.com/Rust-for-Linux/linux/issues/1254#issuecomment-5869573842
> Link: https://github.com/Rust-for-Linux/linux/issues/1254#issuecomment-5869925737
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: chenhan <chenhan0017.work@gmail.com>
> ---
> Changes in v2:
> - Put the checks directly in div() and rem_nanos(), following Tomonori's
> suggestion. Each proposed helper had only one caller, and no other
> concrete users were found to justify a math module.
Even so, I think we should get the math module started and move the
division helpers there. This discussion is not the first on this
problem. Having the helpers available will help everyone, and create
precedence for further helpers down the line.
Best regards,
Andreas Hindborg
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] rust: time: make Delta division and remainder fail consistently
2026-10-01 8:10 ` Andreas Hindborg
@ 2026-10-01 9:31 ` FUJITA Tomonori
2026-10-01 10:10 ` Andreas Hindborg
0 siblings, 1 reply; 5+ messages in thread
From: FUJITA Tomonori @ 2026-10-01 9:31 UTC (permalink / raw)
To: a.hindborg
Cc: chenhan0017.work, rust-for-linux, boqun, fujita.tomonori,
frederic, lyude, tglx, anna-maria, jstultz, sboyd, ojeda, gary,
bjorn3_gh, lossin, aliceryhl, tmgross, dakr, daniel.almeida,
tamird, acourbot, work, miguel.ojeda.sandonis, tomo,
georgeandrout13, linux-kernel, stable
On Thu, 01 Oct 2026 10:10:02 +0200
Andreas Hindborg <a.hindborg@kernel.org> wrote:
> "chenhan" <chenhan0017.work@gmail.com> writes:
>
>> Delta's division and rem_nanos() use Rust operators on 64-bit and C
>> helpers on 32-bit. The report shows that rem_nanos(0) can return 10 for
>> a 10 ns dividend on ARMv7, while the same call panics on x86-64. The
>> i64::MIN / -1 case also differs, and neither API documents these inputs.
>>
>> Use Rust's signed division and remainder semantics on both architectures,
>> as discussed in the report. Div should behave like i64 division, and
>> rem_nanos() supplies the corresponding remainder operation with a 32-bit
>> divisor. Both reject zero divisors and i64::MIN with -1, even when Rust
>> overflow checks are disabled.
>>
>> Check these inputs before entering the architecture-specific code and
>> document the panic conditions. This preserves the API signatures and
>> valid-input results, but intentionally makes invalid inputs panic on
>> 32-bit too. No in-tree callers of either API were found at the base
>> commit. Correct the rem_nanos() parameter name to divisor as well.
>>
>> Tested on x86-64 and ARMv7 QEMU with a built-in Rust module that passes
>> runtime operands to both APIs. Separate boots verify each panic case;
>> valid-input tests cover mixed signs, signed extrema and full-width
>> division operands.
>>
>> Fixes: 4521438fb076 ("rust: time: Implement basic arithmetic operations for Delta")
>> Reported-by: Georgios Androutsopoulos <georgeandrout13@gmail.com>
>> Closes: https://github.com/Rust-for-Linux/linux/issues/1254
>> Link: https://github.com/Rust-for-Linux/linux/issues/1254#issuecomment-5869573842
>> Link: https://github.com/Rust-for-Linux/linux/issues/1254#issuecomment-5869925737
>> Cc: stable@vger.kernel.org
>> Assisted-by: LLM
>> Signed-off-by: chenhan <chenhan0017.work@gmail.com>
>> ---
>> Changes in v2:
>> - Put the checks directly in div() and rem_nanos(), following Tomonori's
>> suggestion. Each proposed helper had only one caller, and no other
>> concrete users were found to justify a math module.
>
> Even so, I think we should get the math module started and move the
> division helpers there. This discussion is not the first on this
> problem. Having the helpers available will help everyone, and create
> precedence for further helpers down the line.
I'm not against starting the math module. Uwe asked for div helpers in
pwm_th1520 [1], and I plan to add the math module for them.
However, if this patch is backported to stable, I think it should be
as small as possible. Also, v2 does not add any new div helpers. It
only adds checks to the existing code.
How about merging this fix as is, and adding the math module in a
separate patch?
[1] https://lore.kernel.org/all/20261001.070215.521963012921142699.tomo@flapping.org/
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] rust: time: make Delta division and remainder fail consistently
2026-10-01 9:31 ` FUJITA Tomonori
@ 2026-10-01 10:10 ` Andreas Hindborg
0 siblings, 0 replies; 5+ messages in thread
From: Andreas Hindborg @ 2026-10-01 10:10 UTC (permalink / raw)
To: FUJITA Tomonori
Cc: chenhan0017.work, rust-for-linux, boqun, fujita.tomonori,
frederic, lyude, tglx, anna-maria, jstultz, sboyd, ojeda, gary,
bjorn3_gh, lossin, aliceryhl, tmgross, dakr, daniel.almeida,
tamird, acourbot, work, miguel.ojeda.sandonis, tomo,
georgeandrout13, linux-kernel, stable
"FUJITA Tomonori" <tomo@flapping.org> writes:
> On Thu, 01 Oct 2026 10:10:02 +0200
> Andreas Hindborg <a.hindborg@kernel.org> wrote:
>
>> "chenhan" <chenhan0017.work@gmail.com> writes:
>>
>>> Delta's division and rem_nanos() use Rust operators on 64-bit and C
>>> helpers on 32-bit. The report shows that rem_nanos(0) can return 10 for
>>> a 10 ns dividend on ARMv7, while the same call panics on x86-64. The
>>> i64::MIN / -1 case also differs, and neither API documents these inputs.
>>>
>>> Use Rust's signed division and remainder semantics on both architectures,
>>> as discussed in the report. Div should behave like i64 division, and
>>> rem_nanos() supplies the corresponding remainder operation with a 32-bit
>>> divisor. Both reject zero divisors and i64::MIN with -1, even when Rust
>>> overflow checks are disabled.
>>>
>>> Check these inputs before entering the architecture-specific code and
>>> document the panic conditions. This preserves the API signatures and
>>> valid-input results, but intentionally makes invalid inputs panic on
>>> 32-bit too. No in-tree callers of either API were found at the base
>>> commit. Correct the rem_nanos() parameter name to divisor as well.
>>>
>>> Tested on x86-64 and ARMv7 QEMU with a built-in Rust module that passes
>>> runtime operands to both APIs. Separate boots verify each panic case;
>>> valid-input tests cover mixed signs, signed extrema and full-width
>>> division operands.
>>>
>>> Fixes: 4521438fb076 ("rust: time: Implement basic arithmetic operations for Delta")
>>> Reported-by: Georgios Androutsopoulos <georgeandrout13@gmail.com>
>>> Closes: https://github.com/Rust-for-Linux/linux/issues/1254
>>> Link: https://github.com/Rust-for-Linux/linux/issues/1254#issuecomment-5869573842
>>> Link: https://github.com/Rust-for-Linux/linux/issues/1254#issuecomment-5869925737
>>> Cc: stable@vger.kernel.org
>>> Assisted-by: LLM
>>> Signed-off-by: chenhan <chenhan0017.work@gmail.com>
>>> ---
>>> Changes in v2:
>>> - Put the checks directly in div() and rem_nanos(), following Tomonori's
>>> suggestion. Each proposed helper had only one caller, and no other
>>> concrete users were found to justify a math module.
>>
>> Even so, I think we should get the math module started and move the
>> division helpers there. This discussion is not the first on this
>> problem. Having the helpers available will help everyone, and create
>> precedence for further helpers down the line.
>
> I'm not against starting the math module. Uwe asked for div helpers in
> pwm_th1520 [1], and I plan to add the math module for them.
>
> However, if this patch is backported to stable, I think it should be
> as small as possible. Also, v2 does not add any new div helpers. It
> only adds checks to the existing code.
>
> How about merging this fix as is, and adding the math module in a
> separate patch?
I'm not a stable expert, but I think adding the math module on stable
should be fine?
If you really want to, I guess we could have this patch be a 2-patch
series with this as the first patch with the stable Cc and then the 2nd
patch moving the code to the helpers from v1, but placed in the math
module.
Then we can pick patch 1 for fixes and have plenty time to discuss patch
2?
Best regards,
Andreas Hindborg
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2] rust: time: make Delta division and remainder fail consistently
2026-10-01 4:29 ` [PATCH v2] rust: time: make Delta division and remainder fail consistently chenhan
2026-10-01 8:10 ` Andreas Hindborg
@ 2026-10-01 10:46 ` Miguel Ojeda
1 sibling, 0 replies; 5+ messages in thread
From: Miguel Ojeda @ 2026-10-01 10:46 UTC (permalink / raw)
To: chenhan
Cc: rust-for-linux, a.hindborg, boqun, fujita.tomonori, frederic,
lyude, tglx, anna-maria, jstultz, sboyd, ojeda, gary, bjorn3_gh,
lossin, aliceryhl, tmgross, dakr, daniel.almeida, tamird,
acourbot, work, tomo, georgeandrout13, linux-kernel, stable
On Thu, Oct 1, 2026 at 6:29 AM chenhan <chenhan0017.work@gmail.com> wrote:
>
> commit. Correct the rem_nanos() parameter name to divisor as well.
This seems like it should be a first patch.
> Link: https://github.com/Rust-for-Linux/linux/issues/1254#issuecomment-5869573842
> Link: https://github.com/Rust-for-Linux/linux/issues/1254#issuecomment-5869925737
The discussion is small enough, so I am not sure why we need the two
Link:s. They can be useful if you want to reference something in
particular, using e.g. the square brackets notation [1] to point to
them.
> On the MIN / -1 safety question: div_s64_rem() computes a quotient even
> though the caller discards it. V1 already checked this input before the C
> call; v2 keeps the guard and makes the representable-quotient condition
> explicit in the SAFETY comment.
Yes, that is fine -- what I meant is that even if we had the check,
the `// SAFETY` comment should still justify why it is not UB (please
see below).
> - // SAFETY: This function is always safe to call regardless of the input values
> + // SAFETY: The divisor is non-zero and the quotient is representable.
"representable" is a fine way to succinctly put it, but I wonder if it
would be better to just spell the condition.
In any case, safety comment need to explain *why* those conditions are
true, not just re-state them (otherwise, safety comments would be a
repetition of the `# Safety` documentation of the function called, and
thus not useful). In other words, the point is that they explain why
something is supposed to hold.
> - /// Return `self % dividend` where `dividend` is in nanoseconds.
> + /// Return `self % divisor`, where `divisor` is a number of nanoseconds.
"a number of" seems to be added spuriously -- please try not to do
unrelated changes, or you do them, please add as new commits (e.g.
this one wouldn't be a fix to backport).
> + /// The divisor is an [`i32`] because `div_s64_rem()`, used on 32-bit
> + /// platforms, takes a signed 32-bit divisor. The dividend remains an [`i64`].
Do we need this in the public documentation?
> + /// Panics if `divisor` is zero, or if `self` represents [`i64::MIN`]
> + /// nanoseconds and `divisor` is `-1`, matching Rust's signed remainder
> + /// operator even though the remainder would be zero.
Not sure if we need the "even though ..." bit.
Thanks!
Cheers,
Miguel
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-10-01 10:47 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <6z5gg2l6ctq6aQIEoJ5hBjZr03ffUqGeECNSGQcVv5eyiZz35kWClxv9o5N7Y-PPk2R2dgpdDxEDLfG7GpkGog==@protonmail.internalid>
2026-10-01 4:29 ` [PATCH v2] rust: time: make Delta division and remainder fail consistently chenhan
2026-10-01 8:10 ` Andreas Hindborg
2026-10-01 9:31 ` FUJITA Tomonori
2026-10-01 10:10 ` Andreas Hindborg
2026-10-01 10:46 ` Miguel Ojeda
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®