cpython: 7bc2923a41b6 (original) (raw)
--- a/Lib/test/test_resource.py +++ b/Lib/test/test_resource.py @@ -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:[](#l1.11)
def __len__(self):[](#l1.12)
return 2[](#l1.13)
def __getitem__(self, key):[](#l1.14)
return limits[key] - 1 # new reference[](#l1.15)
limits = resource.getrlimit(resource.RLIMIT_AS)[](#l1.17)
self.assertEqual(resource.prlimit(0, resource.RLIMIT_AS, BadSeq()),[](#l1.18)
limits)[](#l1.19)
+ def test_main(verbose=None): support.run_unittest(ResourceTest)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -35,6 +35,9 @@ Core and Builtins Library ------- +- Issue #20191: Fixed a crash in resource.prlimit() when pass a sequence that
- Issue #28779: multiprocessing.set_forkserver_preload() would crash the forkserver process if a preloaded module instantiated some multiprocessing objects such as locks.
--- a/Modules/resource.c +++ b/Modules/resource.c @@ -107,29 +107,46 @@ resource_getrusage(PyObject *self, PyObj } 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 */[](#l3.13)
return -1;[](#l3.14)
- if (PyTuple_GET_SIZE(limits) != 2) {
PyErr_SetString(PyExc_ValueError,[](#l3.17)
"expected a tuple of 2 integers");[](#l3.18)
goto error;[](#l3.19)
- }
- 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;[](#l3.26)
rl_out->rlim_max = PyLong_AsLong(maxobj); if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())goto error;[](#l3.27)
return -1;[](#l3.30)
goto error;[](#l3.31)
#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;[](#l3.36)
rl_out->rlim_max = PyLong_AsLongLong(maxobj); if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())goto error;[](#l3.37)
return -1;[](#l3.40)
goto error;[](#l3.41)
- 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* @@ -170,7 +187,7 @@ resource_setrlimit(PyObject *self, PyObj { struct rlimit rl; int resource;
if (!PyArg_ParseTuple(args, "iO:setrlimit", &resource, &limits)) return NULL; @@ -181,21 +198,8 @@ resource_setrlimit(PyObject *self, PyObj return NULL; }
- if (PyTuple_GET_SIZE(limits) != 2) {
PyErr_SetString(PyExc_ValueError,[](#l3.75)
"expected a tuple of 2 integers");[](#l3.76)
goto error;[](#l3.77)
- }
- curobj = PyTuple_GET_ITEM(limits, 0);
- maxobj = PyTuple_GET_ITEM(limits, 1);
- if (py2rlimit(curobj, maxobj, &rl) < 0) {
} if (setrlimit(resource, &rl) == -1) { @@ -207,15 +211,9 @@ resource_setrlimit(PyObject *self, PyObj "not allowed to raise maximum limit"); else PyErr_SetFromErrno(PyExc_OSError);goto error;[](#l3.83)
goto error;[](#l3.91)
} #ifdef HAVE_PRLIMIT @@ -225,10 +223,10 @@ resource_prlimit(PyObject *self, PyObjec struct rlimit old_limit, new_limit; int resource, retval; pid_t pid;
- if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i|(OO):prlimit",
&pid, &resource, &curobj, &maxobj))[](#l3.113)
- if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i|O:prlimit",
&pid, &resource, &limits))[](#l3.115) return NULL;[](#l3.116)
if (resource < 0 || resource >= RLIM_NLIMITS) { @@ -237,8 +235,8 @@ resource_prlimit(PyObject *self, PyObjec return NULL; }