]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #20191: Fixed a crash in resource.prlimit() when pass a sequence that
authorSerhiy Storchaka <storchaka@gmail.com>
Mon, 19 Dec 2016 06:04:15 +0000 (08:04 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Mon, 19 Dec 2016 06:04:15 +0000 (08:04 +0200)
doesn't own its elements as limits.

Lib/test/test_resource.py
Misc/NEWS
Modules/resource.c

index 2ecae0fc450a182b8c5bf47f49f86b60f1dcfda7..cc9c57024dee8e2ac98de38d454437ad645afe47 100644 (file)
@@ -158,6 +158,20 @@ class ResourceTest(unittest.TestCase):
         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)
index 6a29ec8cdbfc6c5d397dc1b4334b04964ae61a23..13e9e6d53dab8f94f8da0b0cb30ed48097a9cbf8 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -130,6 +130,9 @@ Core and Builtins
 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.
index 3a1cf094c75e3d1204db2a07724947f984c86577..970ee84f8e4bce36e5050c2024701d3985c495e6 100644 (file)
@@ -107,29 +107,46 @@ resource_getrusage(PyObject *self, PyObject *args)
 }
 
 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 @@ resource_setrlimit(PyObject *self, PyObject *args)
 {
     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 @@ resource_setrlimit(PyObject *self, PyObject *args)
         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 @@ resource_setrlimit(PyObject *self, PyObject *args)
                             "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 @@ resource_prlimit(PyObject *self, PyObject *args)
     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 @@ resource_prlimit(PyObject *self, PyObject *args)
         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);