Skip to content
This repository has been archived by the owner on Jul 9, 2023. It is now read-only.

Types for checked arithmetic on instants and durations #27

Closed
dtolnay opened this issue Feb 17, 2019 · 4 comments
Closed

Types for checked arithmetic on instants and durations #27

dtolnay opened this issue Feb 17, 2019 · 4 comments

Comments

@dtolnay
Copy link
Owner

dtolnay commented Feb 17, 2019

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(...);
@taiki-e
Copy link

taiki-e commented Feb 19, 2019

I ended up the basic implementation of this : https://github.com/taiki-e/easytime

(I would like to confirm that there is not much difference from what this issue aims.)

@dtolnay
Copy link
Owner Author

dtolnay commented Feb 19, 2019

Nice, looks good to me. I will close out this issue once your crate is published.

I filed taiki-e/easytime#1 to consider adding example code.

@taiki-e
Copy link

taiki-e commented Feb 19, 2019

Thanks, done: https://crates.io/crates/easytime

@dtolnay
Copy link
Owner Author

dtolnay commented Feb 19, 2019

Excellent. I added a link to your crate from the readme.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants