From e2926b72488596f59e43c27f3b7cedf0c5b9e88e Mon Sep 17 00:00:00 2001 From: Michael Felt Date: Fri, 28 Dec 2018 14:57:37 +0100 Subject: [PATCH] bpo-34373: fix test_mktime and test_pthread_getcpuclickid tests on AIX (GH-8726) * Fix test_mktime on AIX by adding code to get mktime to behave the same way as it does on other *nix systems * Fix test_pthread_getcpuclickid in AIX by adjusting the test case expectations when running on AIX in 32-bit mode Patch by Michael Felt. --- Lib/test/test_time.py | 15 +++---- .../2018-08-10-16-17-51.bpo-34373.SKdb1k.rst | 3 ++ Modules/timemodule.c | 45 ++++++++++++++----- Python/pytime.c | 14 ++++++ 4 files changed, 57 insertions(+), 20 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2018-08-10-16-17-51.bpo-34373.SKdb1k.rst diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 2f0665a42ce..136ad29e20a 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -119,7 +119,13 @@ class TimeTestCase(unittest.TestCase): def test_pthread_getcpuclockid(self): clk_id = time.pthread_getcpuclockid(threading.get_ident()) self.assertTrue(type(clk_id) is int) - self.assertNotEqual(clk_id, time.CLOCK_THREAD_CPUTIME_ID) + # when in 32-bit mode AIX only returns the predefined constant + if not platform.system() == "AIX": + self.assertNotEqual(clk_id, time.CLOCK_THREAD_CPUTIME_ID) + elif (sys.maxsize.bit_length() > 32): + self.assertNotEqual(clk_id, time.CLOCK_THREAD_CPUTIME_ID) + else: + self.assertEqual(clk_id, time.CLOCK_THREAD_CPUTIME_ID) t1 = time.clock_gettime(clk_id) t2 = time.clock_gettime(clk_id) self.assertLessEqual(t1, t2) @@ -424,13 +430,6 @@ class TimeTestCase(unittest.TestCase): def test_mktime(self): # Issue #1726687 for t in (-2, -1, 0, 1): - if sys.platform.startswith('aix') and t == -1: - # Issue #11188, #19748: mktime() returns -1 on error. On Linux, - # the tm_wday field is used as a sentinel () to detect if -1 is - # really an error or a valid timestamp. On AIX, tm_wday is - # unchanged even on success and so cannot be used as a - # sentinel. - continue try: tt = time.localtime(t) except (OverflowError, OSError): diff --git a/Misc/NEWS.d/next/Tests/2018-08-10-16-17-51.bpo-34373.SKdb1k.rst b/Misc/NEWS.d/next/Tests/2018-08-10-16-17-51.bpo-34373.SKdb1k.rst new file mode 100644 index 00000000000..1df5449eced --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2018-08-10-16-17-51.bpo-34373.SKdb1k.rst @@ -0,0 +1,3 @@ +Fix ``test_mktime`` and ``test_pthread_getcpuclickid`` tests for AIX +Add range checking for ``_PyTime_localtime`` for AIX +Patch by Michael Felt diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 01bb430ece6..cf6522927ad 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -174,10 +174,15 @@ static PyObject * time_clock_gettime(PyObject *self, PyObject *args) { int ret; - int clk_id; struct timespec tp; +#if defined(_AIX) && (SIZEOF_LONG == 8) + long clk_id; + if (!PyArg_ParseTuple(args, "l:clock_gettime", &clk_id)) { +#else + int clk_id; if (!PyArg_ParseTuple(args, "i:clock_gettime", &clk_id)) { +#endif return NULL; } @@ -972,35 +977,51 @@ time_mktime(PyObject *self, PyObject *tup) { struct tm buf; time_t tt; +#ifdef _AIX + time_t clk; + int year = buf.tm_year; + int delta_days = 0; +#endif + if (!gettmarg(tup, &buf, "iiiiiiiii;mktime(): illegal time tuple argument")) { return NULL; } -#ifdef _AIX +#ifndef _AIX + buf.tm_wday = -1; /* sentinel; original value ignored */ + tt = mktime(&buf); +#else /* year < 1902 or year > 2037 */ - if (buf.tm_year < 2 || buf.tm_year > 137) { + if ((buf.tm_year < 2) || (buf.tm_year > 137)) { /* Issue #19748: On AIX, mktime() doesn't report overflow error for * timestamp < -2^31 or timestamp > 2**31-1. */ PyErr_SetString(PyExc_OverflowError, "mktime argument out of range"); return NULL; } -#else - buf.tm_wday = -1; /* sentinel; original value ignored */ + year = buf.tm_year; + /* year < 1970 - adjust buf.tm_year into legal range */ + while (buf.tm_year < 70) { + buf.tm_year += 4; + delta_days -= (366 + (365 * 3)); + } + + buf.tm_wday = -1; + clk = mktime(&buf); + buf.tm_year = year; + + if ((buf.tm_wday != -1) && delta_days) + buf.tm_wday = (buf.tm_wday + delta_days) % 7; + + tt = clk + (delta_days * (24 * 3600)); #endif - tt = mktime(&buf); /* Return value of -1 does not necessarily mean an error, but tm_wday * cannot remain set to -1 if mktime succeeded. */ if (tt == (time_t)(-1) -#ifndef _AIX /* Return value of -1 does not necessarily mean an error, but * tm_wday cannot remain set to -1 if mktime succeeded. */ - && buf.tm_wday == -1 -#else - /* on AIX, tm_wday is always sets, even on error */ -#endif - ) + && buf.tm_wday == -1) { PyErr_SetString(PyExc_OverflowError, "mktime argument out of range"); diff --git a/Python/pytime.c b/Python/pytime.c index 0e941317419..68c49a86da2 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -1062,6 +1062,20 @@ _PyTime_localtime(time_t t, struct tm *tm) } return 0; #else /* !MS_WINDOWS */ +#ifdef _AIX + /* AIX does not return NULL on an error + so test ranges - asif! + (1902-01-01, -2145916800.0) + (2038-01-01, 2145916800.0) */ + if (abs(t) > (time_t) 2145916800) { +#ifdef EINVAL + errno = EINVAL; +#endif + PyErr_SetString(PyExc_OverflowError, + "ctime argument out of range"); + return -1; + } +#endif if (localtime_r(&t, tm) == NULL) { #ifdef EINVAL if (errno == 0) {