[Python-checkins] bpo-34373: fix test_mktime and test_pthread_getcpuclickid tests on AIX (GH-8726)

Nick Coghlan webhook-mailer at python.org
Fri Dec 28 08:57:49 EST 2018


https://github.com/python/cpython/commit/e2926b72488596f59e43c27f3b7cedf0c5b9e88e
commit: e2926b72488596f59e43c27f3b7cedf0c5b9e88e
branch: master
author: Michael Felt <aixtools at users.noreply.github.com>
committer: Nick Coghlan <ncoghlan at gmail.com>
date: 2018-12-28T23:57:37+10:00
summary:

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.

files:
A Misc/NEWS.d/next/Tests/2018-08-10-16-17-51.bpo-34373.SKdb1k.rst
M Lib/test/test_time.py
M Modules/timemodule.c
M Python/pytime.c

diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py
index 2f0665a42ce4..136ad29e20ad 100644
--- a/Lib/test/test_time.py
+++ b/Lib/test/test_time.py
@@ -119,7 +119,13 @@ def test_clock_monotonic(self):
     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 @@ def test_localtime_without_arg(self):
     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 000000000000..1df5449eced6
--- /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 01bb430ece60..cf6522927ada 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 0e9413174195..68c49a86da25 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) {



More information about the Python-checkins mailing list