[Python-checkins] cpython (3.5): Issue #20191: Fixed a crash in resource.prlimit() when pass a sequence that

serhiy.storchaka python-checkins at python.org
Mon Dec 19 01:07:49 EST 2016


https://hg.python.org/cpython/rev/dac72bc14c00
changeset:   105730:dac72bc14c00
branch:      3.5
parent:      105727:6f89f5eb4422
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Mon Dec 19 08:04:15 2016 +0200
summary:
  Issue #20191: Fixed a crash in resource.prlimit() when pass a sequence that
doesn't own its elements as limits.

files:
  Lib/test/test_resource.py |  14 +++++
  Misc/NEWS                 |   3 +
  Modules/resource.c        |  64 +++++++++++++-------------
  3 files changed, 48 insertions(+), 33 deletions(-)


diff --git a/Lib/test/test_resource.py b/Lib/test/test_resource.py
--- a/Lib/test/test_resource.py
+++ b/Lib/test/test_resource.py
@@ -158,6 +158,20 @@
         self.assertEqual(resource.prlimit(0, resource.RLIMIT_AS, limit),
                          limit)
 
+    # Issue 20191: Reference counting bug
+    @unittest.skipUnless(hasattr(resource, 'prlimit'), 'no prlimit')
+    @support.requires_linux_version(2, 6, 36)
+    def test_prlimit_refcount(self):
+        class BadSeq:
+            def __len__(self):
+                return 2
+            def __getitem__(self, key):
+                return limits[key] - 1  # new reference
+
+        limits = resource.getrlimit(resource.RLIMIT_AS)
+        self.assertEqual(resource.prlimit(0, resource.RLIMIT_AS, BadSeq()),
+                         limits)
+
 
 def test_main(verbose=None):
     support.run_unittest(ResourceTest)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -130,6 +130,9 @@
 Library
 -------
 
+- Issue #20191: Fixed a crash in resource.prlimit() when pass a sequence that
+  doesn't own its elements as limits.
+
 - Issue #28779: multiprocessing.set_forkserver_preload() would crash the
   forkserver process if a preloaded module instantiated some
   multiprocessing objects such as locks.
diff --git a/Modules/resource.c b/Modules/resource.c
--- a/Modules/resource.c
+++ b/Modules/resource.c
@@ -107,29 +107,46 @@
 }
 
 static int
-py2rlimit(PyObject *curobj, PyObject *maxobj, struct rlimit *rl_out)
+py2rlimit(PyObject *limits, struct rlimit *rl_out)
 {
+    PyObject *curobj, *maxobj;
+    limits = PySequence_Tuple(limits);
+    if (!limits)
+        /* Here limits is a borrowed reference */
+        return -1;
+
+    if (PyTuple_GET_SIZE(limits) != 2) {
+        PyErr_SetString(PyExc_ValueError,
+                        "expected a tuple of 2 integers");
+        goto error;
+    }
+    curobj = PyTuple_GET_ITEM(limits, 0);
+    maxobj = PyTuple_GET_ITEM(limits, 1);
 #if !defined(HAVE_LARGEFILE_SUPPORT)
     rl_out->rlim_cur = PyLong_AsLong(curobj);
     if (rl_out->rlim_cur == (rlim_t)-1 && PyErr_Occurred())
-        return -1;
+        goto error;
     rl_out->rlim_max = PyLong_AsLong(maxobj);
     if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())
-        return -1;
+        goto error;
 #else
     /* The limits are probably bigger than a long */
     rl_out->rlim_cur = PyLong_AsLongLong(curobj);
     if (rl_out->rlim_cur == (rlim_t)-1 && PyErr_Occurred())
-        return -1;
+        goto error;
     rl_out->rlim_max = PyLong_AsLongLong(maxobj);
     if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())
-        return -1;
+        goto error;
 #endif
 
+    Py_DECREF(limits);
     rl_out->rlim_cur = rl_out->rlim_cur & RLIM_INFINITY;
     rl_out->rlim_max = rl_out->rlim_max & RLIM_INFINITY;
     return 0;
 
+error:
+    Py_DECREF(limits);
+    return -1;
 }
 
 static PyObject*
@@ -172,7 +189,7 @@
 {
     struct rlimit rl;
     int resource;
-    PyObject *limits, *curobj, *maxobj;
+    PyObject *limits;
 
     if (!PyArg_ParseTuple(args, "iO:setrlimit", &resource, &limits))
         return NULL;
@@ -183,21 +200,8 @@
         return NULL;
     }
 
-    limits = PySequence_Tuple(limits);
-    if (!limits)
-        /* Here limits is a borrowed reference */
+    if (py2rlimit(limits, &rl) < 0) {
         return NULL;
-
-    if (PyTuple_GET_SIZE(limits) != 2) {
-        PyErr_SetString(PyExc_ValueError,
-                        "expected a tuple of 2 integers");
-        goto error;
-    }
-    curobj = PyTuple_GET_ITEM(limits, 0);
-    maxobj = PyTuple_GET_ITEM(limits, 1);
-
-    if (py2rlimit(curobj, maxobj, &rl) < 0) {
-        goto error;
     }
 
     if (setrlimit(resource, &rl) == -1) {
@@ -209,15 +213,9 @@
                             "not allowed to raise maximum limit");
         else
             PyErr_SetFromErrno(PyExc_OSError);
-        goto error;
+        return NULL;
     }
-    Py_DECREF(limits);
-    Py_INCREF(Py_None);
-    return Py_None;
-
-  error:
-    Py_DECREF(limits);
-    return NULL;
+    Py_RETURN_NONE;
 }
 
 #ifdef HAVE_PRLIMIT
@@ -227,10 +225,10 @@
     struct rlimit old_limit, new_limit;
     int resource, retval;
     pid_t pid;
-    PyObject *curobj=NULL, *maxobj=NULL;
+    PyObject *limits = NULL;
 
-    if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i|(OO):prlimit",
-                          &pid, &resource, &curobj, &maxobj))
+    if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i|O:prlimit",
+                          &pid, &resource, &limits))
         return NULL;
 
     if (resource < 0 || resource >= RLIM_NLIMITS) {
@@ -239,8 +237,8 @@
         return NULL;
     }
 
-    if (curobj != NULL) {
-        if (py2rlimit(curobj, maxobj, &new_limit) < 0) {
+    if (limits != NULL) {
+        if (py2rlimit(limits, &new_limit) < 0) {
             return NULL;
         }
         retval = prlimit(pid, resource, &new_limit, &old_limit);

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list