Skip to content

Commit e6da3e6

Browse files
committed
REVIEW ME Avoid overflow from 64-bit A * B / C in std::sys::windows::time.
I should check if this method for "safer" multiplication by a ratio is already provided somewhere in `core::num`. (And if not, add it.) Also, I should look into whether I have any better options here, and whether I should just be calling the WrappingOps or OverflowingOps anyway. But this should serve for the short term.
1 parent a05148f commit e6da3e6

File tree

1 file changed

+27
-1
lines changed

1 file changed

+27
-1
lines changed

src/libstd/sys/windows/time.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,33 @@ impl SteadyTime {
2424
}
2525

2626
pub fn ns(&self) -> u64 {
27-
self.t as u64 * 1_000_000_000 / frequency() as u64
27+
// Want to multiply self.t by the ratio `1_000_000_000 / frequency()`,
28+
// but want to avoid overflow on the multiply.
29+
// Solution: split self.t into separate high- and low-order parts:
30+
// T = A * 2^32 + B
31+
//
32+
// (A * 2^32 + B) * G / F
33+
// =
34+
// A * G / F * 2^32 + B * G / F
35+
// =
36+
// (A * G div F + A * G rem F / F) * 2^32 + B * G / F
37+
// =
38+
// A * G div F * 2^32 + A * G rem F * 2^32 / F + B * G / F
39+
// =
40+
// A * G div F * 2^32 + (A * G rem F * 2^32 + B * G) / F
41+
// ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42+
// hi lo
43+
44+
let f = frequency() as u64;
45+
let g = 1_000_000_000;
46+
let a = (self.t as u64) >> 32;
47+
let b = (self.t as u64) & 0xFFFF_FFFF;
48+
let ag = a * g;
49+
50+
let hi = ag / f << 32;
51+
let lo = ((ag % f << 32) + b * g) / f;
52+
53+
hi + lo
2854
}
2955
}
3056

0 commit comments

Comments
 (0)