Skip to content

Commit 9be79bc

Browse files
committed
Use finite times and intercept time.sleep
1 parent 4a2aa6c commit 9be79bc

File tree

3 files changed

+50
-17
lines changed

3 files changed

+50
-17
lines changed

crosshair/libimpl/timelib.py

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,45 @@
11
import time as real_time
22
from inspect import Signature
33
from math import isfinite
4-
from typing import Any, Callable
4+
from typing import Any, Literal
55

6-
from crosshair.core import FunctionInterps
6+
from crosshair.core import register_patch
77
from crosshair.register_contract import register_contract
88
from crosshair.statespace import context_statespace
99
from crosshair.tracers import NoTracing
1010

1111

12-
def _gte_last(fn: Callable, value: Any) -> bool:
12+
class EarliestPossibleTime:
13+
monotonic: float = 0.0
14+
process_time: float = 0.0
15+
16+
def __init__(self, *a):
17+
pass
18+
19+
20+
# Imprecision at high values becomes a sort of artificial problem
21+
_UNREALISTICALLY_LARGE_TIME_FLOAT = float(60 * 60 * 24 * 365 * 100_000)
22+
23+
24+
def _gte_last(kind: Literal["monotonic", "process_time"], value: Any) -> bool:
25+
with NoTracing():
26+
earliest_times = context_statespace().extra(EarliestPossibleTime)
27+
threshold = getattr(earliest_times, kind)
28+
setattr(earliest_times, kind, value)
29+
return all([threshold <= value, value < _UNREALISTICALLY_LARGE_TIME_FLOAT])
30+
31+
32+
def _sleep(value: float) -> None:
1333
with NoTracing():
14-
interps = context_statespace().extra(FunctionInterps)
15-
previous = interps._interpretations[fn]
16-
if len(previous) < 2:
17-
return True
18-
return value >= previous[-2]
34+
earliest_times = context_statespace().extra(EarliestPossibleTime)
35+
earliest_times.monotonic += value
36+
return None
1937

2038

2139
def make_registrations():
2240
register_contract(
2341
real_time.time,
24-
post=lambda __return__: __return__ > 0.0,
42+
post=lambda __return__: __return__ > 0.0 and isfinite(__return__),
2543
sig=Signature(parameters=[], return_annotation=float),
2644
)
2745
register_contract(
@@ -31,23 +49,24 @@ def make_registrations():
3149
)
3250
register_contract(
3351
real_time.monotonic,
34-
post=lambda __return__: isfinite(__return__)
35-
and _gte_last(real_time.monotonic, __return__),
52+
post=lambda __return__: _gte_last("monotonic", __return__)
53+
and isfinite(__return__),
3654
sig=Signature(parameters=[], return_annotation=float),
3755
)
3856
register_contract(
3957
real_time.monotonic_ns,
40-
post=lambda __return__: isfinite(__return__)
41-
and _gte_last(real_time.monotonic_ns, __return__),
58+
post=lambda __return__: _gte_last("monotonic", __return__ / 1_000_000_000),
4259
sig=Signature(parameters=[], return_annotation=int),
4360
)
4461
register_contract(
4562
real_time.process_time,
46-
post=lambda __return__: _gte_last(real_time.process_time, __return__),
63+
post=lambda __return__: _gte_last("process_time", __return__)
64+
and isfinite(__return__),
4765
sig=Signature(parameters=[], return_annotation=float),
4866
)
4967
register_contract(
5068
real_time.process_time_ns,
51-
post=lambda __return__: _gte_last(real_time.process_time_ns, __return__),
69+
post=lambda __return__: _gte_last("process_time", __return__ / 1_000_000_000),
5270
sig=Signature(parameters=[], return_annotation=int),
5371
)
72+
register_patch(real_time.sleep, _sleep)

crosshair/libimpl/timelib_test.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import pytest
44

5-
from crosshair.statespace import CONFIRMED, POST_FAIL
5+
from crosshair.statespace import CANNOT_CONFIRM, CONFIRMED, POST_FAIL
66
from crosshair.test_util import check_states
77

88

@@ -69,4 +69,14 @@ def f():
6969
start = time.monotonic_ns()
7070
return time.monotonic_ns() - start
7171

72-
check_states(f, CONFIRMED)
72+
check_states(f, CANNOT_CONFIRM)
73+
74+
75+
def test_sleep():
76+
def f():
77+
"""post: _ >= 60.0"""
78+
start = time.monotonic()
79+
time.sleep(60.01)
80+
return time.monotonic() - start
81+
82+
check_states(f, CANNOT_CONFIRM)

doc/source/changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ Version 0.0.85
1414

1515
* Do not always realize symbolic booleans on identity comparisons.
1616
* Start making preparations for Python 3.14 (as of alpha 6)
17+
* Do not let time functions return ``float("inf")``
18+
(fixes `#345 <https://github.com/pschanely/CrossHair/issues/345>`__)
19+
* Do not actually sleep when encountering ``time.sleep()``!
20+
(fixes `#346 <https://github.com/pschanely/CrossHair/issues/346>`__)
1721

1822

1923
Version 0.0.84

0 commit comments

Comments
 (0)