Commit 93fd4782 authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

faulthandler: use _PyTime_t rather than double for timeout (#4139)

Use the _PyTime_t type rather than double for the faulthandler
timeout in dump_traceback_later().

This change should fix the following Coverity warning:

CID 1420311:  Incorrect expression  (UNINTENDED_INTEGER_DIVISION)
Dividing integer expressions "9223372036854775807LL" and "1000LL",
and then converting the integer quotient to type "double". Any
remainder, or fractional part of the quotient, is ignored.

    if ((timeout * 1e6) >= (double) PY_TIMEOUT_MAX) {

The warning comes from (double)PY_TIMEOUT_MAX with:

    #define PY_TIMEOUT_MAX (PY_LLONG_MAX / 1000)
parent 7351f9e5
...@@ -607,30 +607,33 @@ cancel_dump_traceback_later(void) ...@@ -607,30 +607,33 @@ cancel_dump_traceback_later(void)
} }
} }
#define SEC_TO_US (1000 * 1000)
static char* static char*
format_timeout(double timeout) format_timeout(_PyTime_t us)
{ {
unsigned long us, sec, min, hour; unsigned long sec, min, hour;
double intpart, fracpart;
char buffer[100]; char buffer[100];
fracpart = modf(timeout, &intpart); /* the downcast is safe: the caller check that 0 < us <= LONG_MAX */
sec = (unsigned long)intpart; sec = (unsigned long)(us / SEC_TO_US);
us = (unsigned long)(fracpart * 1e6); us %= SEC_TO_US;
min = sec / 60; min = sec / 60;
sec %= 60; sec %= 60;
hour = min / 60; hour = min / 60;
min %= 60; min %= 60;
if (us != 0) if (us != 0) {
PyOS_snprintf(buffer, sizeof(buffer), PyOS_snprintf(buffer, sizeof(buffer),
"Timeout (%lu:%02lu:%02lu.%06lu)!\n", "Timeout (%lu:%02lu:%02lu.%06u)!\n",
hour, min, sec, us); hour, min, sec, (unsigned int)us);
else }
else {
PyOS_snprintf(buffer, sizeof(buffer), PyOS_snprintf(buffer, sizeof(buffer),
"Timeout (%lu:%02lu:%02lu)!\n", "Timeout (%lu:%02lu:%02lu)!\n",
hour, min, sec); hour, min, sec);
}
return _PyMem_Strdup(buffer); return _PyMem_Strdup(buffer);
} }
...@@ -639,8 +642,8 @@ faulthandler_dump_traceback_later(PyObject *self, ...@@ -639,8 +642,8 @@ faulthandler_dump_traceback_later(PyObject *self,
PyObject *args, PyObject *kwargs) PyObject *args, PyObject *kwargs)
{ {
static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL}; static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL};
double timeout; PyObject *timeout_obj;
PY_TIMEOUT_T timeout_us; _PyTime_t timeout, timeout_us;
int repeat = 0; int repeat = 0;
PyObject *file = NULL; PyObject *file = NULL;
int fd; int fd;
...@@ -650,18 +653,25 @@ faulthandler_dump_traceback_later(PyObject *self, ...@@ -650,18 +653,25 @@ faulthandler_dump_traceback_later(PyObject *self,
size_t header_len; size_t header_len;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"d|iOi:dump_traceback_later", kwlist, "O|iOi:dump_traceback_later", kwlist,
&timeout, &repeat, &file, &exit)) &timeout_obj, &repeat, &file, &exit))
return NULL; return NULL;
if ((timeout * 1e6) >= (double) PY_TIMEOUT_MAX) {
PyErr_SetString(PyExc_OverflowError, "timeout value is too large"); if (_PyTime_FromSecondsObject(&timeout, timeout_obj,
_PyTime_ROUND_TIMEOUT) < 0) {
return NULL; return NULL;
} }
timeout_us = (PY_TIMEOUT_T)(timeout * 1e6); timeout_us = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_TIMEOUT);
if (timeout_us <= 0) { if (timeout_us <= 0) {
PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0"); PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0");
return NULL; return NULL;
} }
/* Limit to LONG_MAX seconds for format_timeout() */
if (timeout_us >= PY_TIMEOUT_MAX || timeout_us / SEC_TO_US >= LONG_MAX) {
PyErr_SetString(PyExc_OverflowError,
"timeout value is too large");
return NULL;
}
tstate = get_thread_state(); tstate = get_thread_state();
if (tstate == NULL) if (tstate == NULL)
...@@ -672,7 +682,7 @@ faulthandler_dump_traceback_later(PyObject *self, ...@@ -672,7 +682,7 @@ faulthandler_dump_traceback_later(PyObject *self,
return NULL; return NULL;
/* format the timeout */ /* format the timeout */
header = format_timeout(timeout); header = format_timeout(timeout_us);
if (header == NULL) if (header == NULL)
return PyErr_NoMemory(); return PyErr_NoMemory();
header_len = strlen(header); header_len = strlen(header);
...@@ -683,7 +693,8 @@ faulthandler_dump_traceback_later(PyObject *self, ...@@ -683,7 +693,8 @@ faulthandler_dump_traceback_later(PyObject *self,
Py_XINCREF(file); Py_XINCREF(file);
Py_XSETREF(thread.file, file); Py_XSETREF(thread.file, file);
thread.fd = fd; thread.fd = fd;
thread.timeout_us = timeout_us; /* the downcast is safe: we check that 0 < timeout_us < PY_TIMEOUT_MAX */
thread.timeout_us = (PY_TIMEOUT_T)timeout_us;
thread.repeat = repeat; thread.repeat = repeat;
thread.interp = tstate->interp; thread.interp = tstate->interp;
thread.exit = exit; thread.exit = exit;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment