Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ae6cd7c

Browse files
authored
bpo-37205: time.time() cannot fail with fatal error (GH-23314)
time.time(), time.perf_counter() and time.monotonic() functions can no longer fail with a Python fatal error, instead raise a regular Python exception on failure. Remove _PyTime_Init(): don't check system, monotonic and perf counter clocks at startup anymore. On error, _PyTime_GetSystemClock(), _PyTime_GetMonotonicClock() and _PyTime_GetPerfCounter() now silently ignore the error and return 0. They cannot fail with a Python fatal error anymore. Add py_mach_timebase_info() and win_perf_counter_frequency() sub-functions.
1 parent 5909a49 commit ae6cd7c

File tree

5 files changed

+228
-158
lines changed

5 files changed

+228
-158
lines changed

Include/pytime.h

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -164,22 +164,6 @@ PyAPI_FUNC(_PyTime_t) _PyTime_MulDiv(_PyTime_t ticks,
164164
_PyTime_t mul,
165165
_PyTime_t div);
166166

167-
/* Get the current time from the system clock.
168-
169-
The function cannot fail. _PyTime_Init() ensures that the system clock
170-
works. */
171-
PyAPI_FUNC(_PyTime_t) _PyTime_GetSystemClock(void);
172-
173-
/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards.
174-
The clock is not affected by system clock updates. The reference point of
175-
the returned value is undefined, so that only the difference between the
176-
results of consecutive calls is valid.
177-
178-
The function cannot fail. _PyTime_Init() ensures that a monotonic clock
179-
is available and works. */
180-
PyAPI_FUNC(_PyTime_t) _PyTime_GetMonotonicClock(void);
181-
182-
183167
/* Structure used by time.get_clock_info() */
184168
typedef struct {
185169
const char *implementation;
@@ -189,13 +173,34 @@ typedef struct {
189173
} _Py_clock_info_t;
190174

191175
/* Get the current time from the system clock.
192-
* Fill clock information if info is not NULL.
193-
* Raise an exception and return -1 on error, return 0 on success.
176+
177+
If the internal clock fails, silently ignore the error and return 0.
178+
On integer overflow, silently ignore the overflow and truncated the clock to
179+
_PyTime_MIN or _PyTime_MAX.
180+
181+
Use _PyTime_GetSystemClockWithInfo() to check for failure. */
182+
PyAPI_FUNC(_PyTime_t) _PyTime_GetSystemClock(void);
183+
184+
/* Get the current time from the system clock.
185+
* On success, set *t and *info (if not NULL), and return 0.
186+
* On error, raise an exception and return -1.
194187
*/
195188
PyAPI_FUNC(int) _PyTime_GetSystemClockWithInfo(
196189
_PyTime_t *t,
197190
_Py_clock_info_t *info);
198191

192+
/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards.
193+
The clock is not affected by system clock updates. The reference point of
194+
the returned value is undefined, so that only the difference between the
195+
results of consecutive calls is valid.
196+
197+
If the internal clock fails, silently ignore the error and return 0.
198+
On integer overflow, silently ignore the overflow and truncated the clock to
199+
_PyTime_MIN or _PyTime_MAX.
200+
201+
Use _PyTime_GetMonotonicClockWithInfo() to check for failure. */
202+
PyAPI_FUNC(_PyTime_t) _PyTime_GetMonotonicClock(void);
203+
199204
/* Get the time of a monotonic clock, i.e. a clock that cannot go backwards.
200205
The clock is not affected by system clock updates. The reference point of
201206
the returned value is undefined, so that only the difference between the
@@ -209,10 +214,6 @@ PyAPI_FUNC(int) _PyTime_GetMonotonicClockWithInfo(
209214
_Py_clock_info_t *info);
210215

211216

212-
/* Initialize time.
213-
Return 0 on success, raise an exception and return -1 on error. */
214-
PyAPI_FUNC(int) _PyTime_Init(void);
215-
216217
/* Converts a timestamp to the Gregorian time, using the local time zone.
217218
Return 0 on success, raise an exception and return -1 on error. */
218219
PyAPI_FUNC(int) _PyTime_localtime(time_t t, struct tm *tm);
@@ -224,8 +225,11 @@ PyAPI_FUNC(int) _PyTime_gmtime(time_t t, struct tm *tm);
224225
/* Get the performance counter: clock with the highest available resolution to
225226
measure a short duration.
226227
227-
The function cannot fail. _PyTime_Init() ensures that the system clock
228-
works. */
228+
If the internal clock fails, silently ignore the error and return 0.
229+
On integer overflow, silently ignore the overflow and truncated the clock to
230+
_PyTime_MIN or _PyTime_MAX.
231+
232+
Use _PyTime_GetPerfCounterWithInfo() to check for failure. */
229233
PyAPI_FUNC(_PyTime_t) _PyTime_GetPerfCounter(void);
230234

231235
/* Get the performance counter: clock with the highest available resolution to
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:func:`time.time()`, :func:`time.perf_counter()` and
2+
:func:`time.monotonic()` functions can no longer fail with a Python fatal
3+
error, instead raise a regular Python exception on failure.

Modules/timemodule.c

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
#define _Py_tzname tzname
5252
#endif
5353

54-
#if defined(__APPLE__ ) && defined(__has_builtin)
54+
#if defined(__APPLE__ ) && defined(__has_builtin)
5555
# if __has_builtin(__builtin_available)
5656
# define HAVE_CLOCK_GETTIME_RUNTIME __builtin_available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)
5757
# endif
@@ -74,10 +74,21 @@ _PyFloat_FromPyTime(_PyTime_t t)
7474
}
7575

7676

77+
static int
78+
get_system_time(_PyTime_t *t)
79+
{
80+
// Avoid _PyTime_GetSystemClock() which silently ignores errors.
81+
return _PyTime_GetSystemClockWithInfo(t, NULL);
82+
}
83+
84+
7785
static PyObject *
7886
time_time(PyObject *self, PyObject *unused)
7987
{
80-
_PyTime_t t = _PyTime_GetSystemClock();
88+
_PyTime_t t;
89+
if (get_system_time(&t) < 0) {
90+
return NULL;
91+
}
8192
return _PyFloat_FromPyTime(t);
8293
}
8394

@@ -91,7 +102,10 @@ Fractions of a second may be present if the system clock provides them.");
91102
static PyObject *
92103
time_time_ns(PyObject *self, PyObject *unused)
93104
{
94-
_PyTime_t t = _PyTime_GetSystemClock();
105+
_PyTime_t t;
106+
if (get_system_time(&t) < 0) {
107+
return NULL;
108+
}
95109
return _PyTime_AsNanosecondsObject(t);
96110
}
97111

@@ -147,20 +161,11 @@ _PyTime_GetClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
147161
}
148162
#endif /* HAVE_CLOCK */
149163

150-
static PyObject*
151-
perf_counter(_Py_clock_info_t *info)
152-
{
153-
_PyTime_t t;
154-
if (_PyTime_GetPerfCounterWithInfo(&t, info) < 0) {
155-
return NULL;
156-
}
157-
return _PyFloat_FromPyTime(t);
158-
}
159164

160165
#ifdef HAVE_CLOCK_GETTIME
161166

162167
#ifdef __APPLE__
163-
/*
168+
/*
164169
* The clock_* functions will be removed from the module
165170
* dict entirely when the C API is not available.
166171
*/
@@ -1096,10 +1101,22 @@ the local timezone used by methods such as localtime, but this behaviour\n\
10961101
should not be relied on.");
10971102
#endif /* HAVE_WORKING_TZSET */
10981103

1104+
1105+
static int
1106+
get_monotonic(_PyTime_t *t)
1107+
{
1108+
// Avoid _PyTime_GetMonotonicClock() which silently ignores errors.
1109+
return _PyTime_GetMonotonicClockWithInfo(t, NULL);
1110+
}
1111+
1112+
10991113
static PyObject *
11001114
time_monotonic(PyObject *self, PyObject *unused)
11011115
{
1102-
_PyTime_t t = _PyTime_GetMonotonicClock();
1116+
_PyTime_t t;
1117+
if (get_monotonic(&t) < 0) {
1118+
return NULL;
1119+
}
11031120
return _PyFloat_FromPyTime(t);
11041121
}
11051122

@@ -1111,7 +1128,10 @@ Monotonic clock, cannot go backward.");
11111128
static PyObject *
11121129
time_monotonic_ns(PyObject *self, PyObject *unused)
11131130
{
1114-
_PyTime_t t = _PyTime_GetMonotonicClock();
1131+
_PyTime_t t;
1132+
if (get_monotonic(&t) < 0) {
1133+
return NULL;
1134+
}
11151135
return _PyTime_AsNanosecondsObject(t);
11161136
}
11171137

@@ -1120,21 +1140,38 @@ PyDoc_STRVAR(monotonic_ns_doc,
11201140
\n\
11211141
Monotonic clock, cannot go backward, as nanoseconds.");
11221142

1143+
1144+
static int
1145+
get_perf_counter(_PyTime_t *t)
1146+
{
1147+
// Avoid _PyTime_GetPerfCounter() which silently ignores errors.
1148+
return _PyTime_GetPerfCounterWithInfo(t, NULL);
1149+
}
1150+
1151+
11231152
static PyObject *
11241153
time_perf_counter(PyObject *self, PyObject *unused)
11251154
{
1126-
return perf_counter(NULL);
1155+
_PyTime_t t;
1156+
if (get_perf_counter(&t) < 0) {
1157+
return NULL;
1158+
}
1159+
return _PyFloat_FromPyTime(t);
11271160
}
11281161

11291162
PyDoc_STRVAR(perf_counter_doc,
11301163
"perf_counter() -> float\n\
11311164
\n\
11321165
Performance counter for benchmarking.");
11331166

1167+
11341168
static PyObject *
11351169
time_perf_counter_ns(PyObject *self, PyObject *unused)
11361170
{
1137-
_PyTime_t t = _PyTime_GetPerfCounter();
1171+
_PyTime_t t;
1172+
if (get_perf_counter(&t) < 0) {
1173+
return NULL;
1174+
}
11381175
return _PyTime_AsNanosecondsObject(t);
11391176
}
11401177

@@ -1421,7 +1458,7 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
14211458

14221459
#if defined(__APPLE__) && defined(__has_attribute) && __has_attribute(availability)
14231460
static int
1424-
_PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
1461+
_PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
14251462
__attribute__((availability(macos, introduced=10.12)))
14261463
__attribute__((availability(ios, introduced=10.0)))
14271464
__attribute__((availability(tvos, introduced=10.0)))
@@ -1460,7 +1497,7 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
14601497

14611498
#ifdef HAVE_THREAD_TIME
14621499
#ifdef __APPLE__
1463-
/*
1500+
/*
14641501
* The clock_* functions will be removed from the module
14651502
* dict entirely when the C API is not available.
14661503
*/
@@ -2025,7 +2062,10 @@ pysleep(_PyTime_t secs)
20252062
HANDLE hInterruptEvent;
20262063
#endif
20272064

2028-
deadline = _PyTime_GetMonotonicClock() + secs;
2065+
if (get_monotonic(&monotonic) < 0) {
2066+
return -1;
2067+
}
2068+
deadline = monotonic + secs;
20292069

20302070
do {
20312071
#ifndef MS_WINDOWS
@@ -2077,10 +2117,13 @@ pysleep(_PyTime_t secs)
20772117
if (PyErr_CheckSignals())
20782118
return -1;
20792119

2080-
monotonic = _PyTime_GetMonotonicClock();
2120+
if (get_monotonic(&monotonic) < 0) {
2121+
return -1;
2122+
}
20812123
secs = deadline - monotonic;
2082-
if (secs < 0)
2124+
if (secs < 0) {
20832125
break;
2126+
}
20842127
/* retry with the recomputed delay */
20852128
} while (1);
20862129

Python/pylifecycle.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -763,12 +763,6 @@ pycore_interp_init(PyThreadState *tstate)
763763
goto done;
764764
}
765765

766-
if (_Py_IsMainInterpreter(tstate)) {
767-
if (_PyTime_Init() < 0) {
768-
return _PyStatus_ERR("can't initialize time");
769-
}
770-
}
771-
772766
status = _PySys_Create(tstate, &sysmod);
773767
if (_PyStatus_EXCEPTION(status)) {
774768
goto done;

0 commit comments

Comments
 (0)