Skip to content

Commit ccc781e

Browse files
authored
Prevent TimeStamps from being modified (#821)
Our `TimeStamp` type is internally an `Instant`. The representation of `Instant` depends on the platform, but for many platforms it internally consists of unsigned numbers. For WASI its worse, because the moment the WASI VM starts, the time starts at 0. This means any subtraction from the time results in a numeric underflow and might panic. To prevent this from happening, `TimeStamp`s can no longer be manually modified, they always represent valid points in time.
1 parent 922cc84 commit ccc781e

File tree

9 files changed

+26
-85
lines changed

9 files changed

+26
-85
lines changed

src/platform/no_std/time.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,6 @@ impl Instant {
5353
}
5454
}
5555

56-
impl Sub<Duration> for Instant {
57-
type Output = Instant;
58-
59-
fn sub(self, rhs: Duration) -> Instant {
60-
Self(self.0 - rhs)
61-
}
62-
}
63-
6456
impl Sub for Instant {
6557
type Output = Duration;
6658

src/platform/normal/mod.rs

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,6 @@ cfg_if::cfg_if! {
127127
}
128128
}
129129

130-
impl Sub<Duration> for Instant {
131-
type Output = Instant;
132-
133-
#[inline]
134-
fn sub(self, rhs: Duration) -> Instant {
135-
Self(self.0 - rhs)
136-
}
137-
}
138-
139130
impl Sub for Instant {
140131
type Output = Duration;
141132

@@ -171,15 +162,6 @@ cfg_if::cfg_if! {
171162
}
172163
}
173164

174-
impl Sub<Duration> for Instant {
175-
type Output = Instant;
176-
177-
#[inline]
178-
fn sub(self, rhs: Duration) -> Instant {
179-
Self((self.0 as i64 - i64::try_from(rhs.whole_nanoseconds()).unwrap()) as u64)
180-
}
181-
}
182-
183165
impl Sub for Instant {
184166
type Output = Duration;
185167

@@ -203,15 +185,6 @@ cfg_if::cfg_if! {
203185
}
204186
}
205187

206-
impl Sub<Duration> for Instant {
207-
type Output = Instant;
208-
209-
#[inline]
210-
fn sub(self, rhs: Duration) -> Instant {
211-
Self(time::ext::InstantExt::sub_signed(self.0, rhs))
212-
}
213-
}
214-
215188
impl Sub for Instant {
216189
type Output = Duration;
217190

src/platform/wasm/unknown/time.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,6 @@ impl Instant {
4141
}
4242
}
4343

44-
impl Sub<Duration> for Instant {
45-
type Output = Instant;
46-
47-
fn sub(self, rhs: Duration) -> Instant {
48-
Self(self.0 - rhs)
49-
}
50-
}
51-
5244
impl Sub for Instant {
5345
type Output = Duration;
5446

src/platform/wasm/web/time.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,6 @@ impl Instant {
8181
}
8282
}
8383

84-
impl Sub<Duration> for Instant {
85-
type Output = Instant;
86-
87-
fn sub(self, rhs: Duration) -> Instant {
88-
Self(self.0 - rhs)
89-
}
90-
}
91-
9284
impl Sub for Instant {
9385
type Output = Duration;
9486

src/timing/time_stamp.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
use crate::{
2-
platform::{Duration, Instant},
3-
TimeSpan,
4-
};
1+
use crate::{platform::Instant, TimeSpan};
52
use core::ops::Sub;
63

74
/// A `TimeStamp` stores a point in time that can be used to calculate a
@@ -26,12 +23,3 @@ impl Sub for TimeStamp {
2623
TimeSpan::from(self.0 - rhs.0)
2724
}
2825
}
29-
30-
impl Sub<TimeSpan> for TimeStamp {
31-
type Output = TimeStamp;
32-
33-
#[inline]
34-
fn sub(self, rhs: TimeSpan) -> TimeStamp {
35-
TimeStamp(self.0 - Duration::from(rhs))
36-
}
37-
}

src/timing/timer/active_attempt.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ use crate::{
66
#[derive(Debug, Clone)]
77
pub struct ActiveAttempt {
88
pub state: State,
9+
/// The date time when the attempt started.
910
pub attempt_started: AtomicDateTime,
11+
/// The time stamp when the attempt started.
1012
pub start_time: TimeStamp,
11-
pub start_time_with_offset: TimeStamp,
12-
// This gets adjusted after resuming
13-
pub adjusted_start_time: TimeStamp,
13+
/// The original offset gets kept around to undo the pauses.
14+
pub original_offset: TimeSpan,
15+
/// The adjusted offset gets modified as pauses get accumulated.
16+
pub adjusted_offset: TimeSpan,
1417
pub game_time_paused_at: Option<TimeSpan>,
1518
pub loading_times: Option<TimeSpan>,
1619
}
@@ -54,9 +57,8 @@ impl ActiveAttempt {
5457
game_time,
5558
};
5659
}
57-
State::NotEnded { time_paused_at, .. } => {
58-
time_paused_at.unwrap_or_else(|| TimeStamp::now() - self.adjusted_start_time)
59-
}
60+
State::NotEnded { time_paused_at, .. } => time_paused_at
61+
.unwrap_or_else(|| TimeStamp::now() - self.start_time + self.adjusted_offset),
6062
};
6163

6264
let game_time = self
@@ -75,11 +77,11 @@ impl ActiveAttempt {
7577
..
7678
} = self.state
7779
{
78-
return Some(TimeStamp::now() - self.start_time_with_offset - pause_time);
80+
return Some(TimeStamp::now() - self.start_time + self.original_offset - pause_time);
7981
}
8082

81-
if self.start_time_with_offset != self.adjusted_start_time {
82-
Some(self.start_time_with_offset - self.adjusted_start_time)
83+
if self.original_offset != self.adjusted_offset {
84+
Some(self.original_offset - self.adjusted_offset)
8385
} else {
8486
None
8587
}
@@ -105,7 +107,7 @@ impl ActiveAttempt {
105107
return Err(Error::TimerPaused);
106108
}
107109

108-
let real_time = TimeStamp::now() - self.adjusted_start_time;
110+
let real_time = TimeStamp::now() - self.start_time + self.adjusted_offset;
109111

110112
if real_time < TimeSpan::zero() {
111113
return Err(Error::NegativeTime);

src/timing/timer/mod.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ impl Timer {
282282
if self.active_attempt.is_none() {
283283
let attempt_started = AtomicDateTime::now();
284284
let start_time = TimeStamp::now();
285-
let start_time_with_offset = start_time - self.run.offset();
285+
let offset = self.run.offset();
286286

287287
self.active_attempt = Some(ActiveAttempt {
288288
state: State::NotEnded {
@@ -291,8 +291,8 @@ impl Timer {
291291
},
292292
attempt_started,
293293
start_time,
294-
start_time_with_offset,
295-
adjusted_start_time: start_time_with_offset,
294+
original_offset: offset,
295+
adjusted_offset: offset,
296296
game_time_paused_at: None,
297297
loading_times: None,
298298
});
@@ -497,7 +497,8 @@ impl Timer {
497497
};
498498

499499
if time_paused_at.is_none() {
500-
*time_paused_at = Some(TimeStamp::now() - active_attempt.adjusted_start_time);
500+
*time_paused_at =
501+
Some(TimeStamp::now() - active_attempt.start_time + active_attempt.adjusted_offset);
501502
Ok(Event::Paused)
502503
} else {
503504
Err(Error::AlreadyPaused)
@@ -513,7 +514,8 @@ impl Timer {
513514
};
514515

515516
if let Some(pause_time) = *time_paused_at {
516-
active_attempt.adjusted_start_time = TimeStamp::now() - pause_time;
517+
active_attempt.adjusted_offset =
518+
pause_time - (TimeStamp::now() - active_attempt.start_time);
517519
*time_paused_at = None;
518520
Ok(Event::Resumed)
519521
} else {
@@ -579,7 +581,7 @@ impl Timer {
579581
};
580582

581583
if let Some(active_attempt) = &mut self.active_attempt {
582-
active_attempt.adjusted_start_time = active_attempt.start_time_with_offset;
584+
active_attempt.adjusted_offset = active_attempt.original_offset;
583585
Ok(event)
584586
} else {
585587
Err(Error::NoRunInProgress)

tests/rendering.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,8 @@ fn actual_split_file() {
180180
check(
181181
&layout.state(&mut image_cache, &timer.snapshot()),
182182
&image_cache,
183-
"42b2292f5c884c17",
184-
"1e4c66359bdc32e8",
183+
"c1e9e757c15a35ae",
184+
"4fe65a630b531c54",
185185
"actual_split_file",
186186
);
187187
}
@@ -228,8 +228,8 @@ fn timer_delta_background() {
228228
&layout.state(&mut image_cache, &timer.snapshot()),
229229
&image_cache,
230230
[250, 300],
231-
"e96525c84aa77f66",
232-
"bd8139d0f625af38",
231+
"748fa26a41a8d5a3",
232+
"8bae1351d0dd52d7",
233233
"timer_delta_background_stopped",
234234
);
235235
}

tests/run_files/livesplit1.0.lss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<GameIcon />
44
<GameName>Pac-Man World 3</GameName>
55
<CategoryName>Any%</CategoryName>
6-
<Offset>00:00:00</Offset>
6+
<Offset>12:34:56</Offset>
77
<AttemptCount>3</AttemptCount>
88
<RunHistory>
99
<Time id="1">

0 commit comments

Comments
 (0)