diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2016-12-19 06:07:29 (GMT) |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2016-12-19 06:07:29 (GMT) |
commit | 932ee73188c73bbe63834f69566a4f188fbf43a7 (patch) | |
tree | e6714c5150ba9fd0939b409f5553aea4c6319ce1 | |
parent | 39d60fa9269e129219077288f10541317f1b9374 (diff) | |
parent | 879199ba11947d9765b06806df54566fde75d498 (diff) | |
download | cpython-932ee73188c73bbe63834f69566a4f188fbf43a7.zip cpython-932ee73188c73bbe63834f69566a4f188fbf43a7.tar.gz cpython-932ee73188c73bbe63834f69566a4f188fbf43a7.tar.bz2 |
Issue #20191: Fixed a crash in resource.prlimit() when pass a sequence that
doesn't own its elements as limits.
-rw-r--r-- | Lib/test/test_resource.py | 14 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | 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 index 2ecae0f..cc9c570 100644 --- 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: + 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) @@ -197,6 +197,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 #16255: subprocess.Popen uses /system/bin/sh on Android as the shell, instead of /bin/sh. diff --git a/Modules/resource.c b/Modules/resource.c index 6702b7a..113ad5c 100644 --- a/Modules/resource.c +++ b/Modules/resource.c @@ -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* @@ -170,7 +187,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; @@ -181,21 +198,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) { @@ -207,15 +211,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 @@ -225,10 +223,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) { @@ -237,8 +235,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); |