summaryrefslogtreecommitdiff
path: root/Modules/faulthandler.c
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2017-10-27 07:27:12 -0700
committerGitHub <noreply@github.com>2017-10-27 07:27:12 -0700
commit93fd478231bba0c00a3561ea8db31774909ec714 (patch)
treece29df5e9b40737873ecf42bfa5ccedda02bc899 /Modules/faulthandler.c
parent7351f9e5a91c403d15c6d556f9989b443f1296f9 (diff)
downloadcpython-git-93fd478231bba0c00a3561ea8db31774909ec714.tar.gz
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)
Diffstat (limited to 'Modules/faulthandler.c')
-rw-r--r--Modules/faulthandler.c51
1 files changed, 31 insertions, 20 deletions
diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
index dba646b128..9b51f7e30a 100644
--- a/Modules/faulthandler.c
+++ b/Modules/faulthandler.c
@@ -607,30 +607,33 @@ cancel_dump_traceback_later(void)
}
}
+#define SEC_TO_US (1000 * 1000)
+
static char*
-format_timeout(double timeout)
+format_timeout(_PyTime_t us)
{
- unsigned long us, sec, min, hour;
- double intpart, fracpart;
+ unsigned long sec, min, hour;
char buffer[100];
- fracpart = modf(timeout, &intpart);
- sec = (unsigned long)intpart;
- us = (unsigned long)(fracpart * 1e6);
+ /* the downcast is safe: the caller check that 0 < us <= LONG_MAX */
+ sec = (unsigned long)(us / SEC_TO_US);
+ us %= SEC_TO_US;
+
min = sec / 60;
sec %= 60;
hour = min / 60;
min %= 60;
- if (us != 0)
+ if (us != 0) {
PyOS_snprintf(buffer, sizeof(buffer),
- "Timeout (%lu:%02lu:%02lu.%06lu)!\n",
- hour, min, sec, us);
- else
+ "Timeout (%lu:%02lu:%02lu.%06u)!\n",
+ hour, min, sec, (unsigned int)us);
+ }
+ else {
PyOS_snprintf(buffer, sizeof(buffer),
"Timeout (%lu:%02lu:%02lu)!\n",
hour, min, sec);
-
+ }
return _PyMem_Strdup(buffer);
}
@@ -639,8 +642,8 @@ faulthandler_dump_traceback_later(PyObject *self,
PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL};
- double timeout;
- PY_TIMEOUT_T timeout_us;
+ PyObject *timeout_obj;
+ _PyTime_t timeout, timeout_us;
int repeat = 0;
PyObject *file = NULL;
int fd;
@@ -650,18 +653,25 @@ faulthandler_dump_traceback_later(PyObject *self,
size_t header_len;
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
- "d|iOi:dump_traceback_later", kwlist,
- &timeout, &repeat, &file, &exit))
+ "O|iOi:dump_traceback_later", kwlist,
+ &timeout_obj, &repeat, &file, &exit))
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;
}
- timeout_us = (PY_TIMEOUT_T)(timeout * 1e6);
+ timeout_us = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_TIMEOUT);
if (timeout_us <= 0) {
PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0");
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();
if (tstate == NULL)
@@ -672,7 +682,7 @@ faulthandler_dump_traceback_later(PyObject *self,
return NULL;
/* format the timeout */
- header = format_timeout(timeout);
+ header = format_timeout(timeout_us);
if (header == NULL)
return PyErr_NoMemory();
header_len = strlen(header);
@@ -683,7 +693,8 @@ faulthandler_dump_traceback_later(PyObject *self,
Py_XINCREF(file);
Py_XSETREF(thread.file, file);
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.interp = tstate->interp;
thread.exit = exit;