-
-
Notifications
You must be signed in to change notification settings - Fork 7
Types for checked arithmetic on instants and durations #27
Description
The std::time::Instant
and std::time::Duration
types are quite tricky to use correctly for arithmetic because their arithmetic operators panic on overflow and their non-panicking methods are unergonomic.
Consider a use case drawn from TURN_Hammer in which we receive untrusted input representing seconds and subsec-nanoseconds elapsed since some prearranged base instant, and we need to compute a value rtt4
which is the duration elapsed since the untrusted moment. Naively the code would be:
let now = Instant::now();
if now > deadline {
break;
}
let s: u64 = /* untrusted */;
let ns: u32 = /* untrusted */;
let since_base = Duration::new(s, ns);
let remote_instant = base_instant + since_base;
let rtt4 = now - remote_instant;
The problem is all three of the last three lines can panic in the face of untrusted input.
let since_base
panics if s + ns / 1e9 > u64::max_value();let remote_instant
panics on overflow;let rtt4
panics if remote_instant > now.
The checked version of the same logic is harder to write and much less readable.
let s = Duration::from_secs(/* untrusted */);
let ns = Duration::from_nanos(/* untrusted */);
let since_base = s.checked_add(ns)?;
let remote_instant = base_instant.checked_add(since_base)?;
let rtt4 = now.checked_duration_since(remote_instant)?;
I would like a library that provides wrapper types for safely performing panic-free checked arithmetic on instants and durations such that the naive readable code is also secure:
use easytime::{Duration, Instant};
let s: u64 = /* untrusted */;
let ns: u32 = /* untrusted */;
let since_base = Duration::new(s, ns);
let rtt4 = now - (base_instant + since_base);
// some method to go from easytime::Duration to std::time::Duration:
let rtt4 = rtt4.unwrap_or(...);