Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 879199b

Browse files
Issue #20191: Fixed a crash in resource.prlimit() when pass a sequence that
doesn't own its elements as limits.
2 parents cd259bf + b94eef2 commit 879199b

3 files changed

Lines changed: 48 additions & 33 deletions

File tree

Lib/test/test_resource.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,20 @@ def test_prlimit(self):
158158
self.assertEqual(resource.prlimit(0, resource.RLIMIT_AS, limit),
159159
limit)
160160

161+
# Issue 20191: Reference counting bug
162+
@unittest.skipUnless(hasattr(resource, 'prlimit'), 'no prlimit')
163+
@support.requires_linux_version(2, 6, 36)
164+
def test_prlimit_refcount(self):
165+
class BadSeq:
166+
def __len__(self):
167+
return 2
168+
def __getitem__(self, key):
169+
return limits[key] - 1 # new reference
170+
171+
limits = resource.getrlimit(resource.RLIMIT_AS)
172+
self.assertEqual(resource.prlimit(0, resource.RLIMIT_AS, BadSeq()),
173+
limits)
174+
161175

162176
def test_main(verbose=None):
163177
support.run_unittest(ResourceTest)

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ Core and Builtins
3535
Library
3636
-------
3737

38+
- Issue #20191: Fixed a crash in resource.prlimit() when pass a sequence that
39+
doesn't own its elements as limits.
40+
3841
- Issue #28779: multiprocessing.set_forkserver_preload() would crash the
3942
forkserver process if a preloaded module instantiated some
4043
multiprocessing objects such as locks.

Modules/resource.c

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -107,29 +107,46 @@ resource_getrusage(PyObject *self, PyObject *args)
107107
}
108108

109109
static int
110-
py2rlimit(PyObject *curobj, PyObject *maxobj, struct rlimit *rl_out)
110+
py2rlimit(PyObject *limits, struct rlimit *rl_out)
111111
{
112+
PyObject *curobj, *maxobj;
113+
limits = PySequence_Tuple(limits);
114+
if (!limits)
115+
/* Here limits is a borrowed reference */
116+
return -1;
117+
118+
if (PyTuple_GET_SIZE(limits) != 2) {
119+
PyErr_SetString(PyExc_ValueError,
120+
"expected a tuple of 2 integers");
121+
goto error;
122+
}
123+
curobj = PyTuple_GET_ITEM(limits, 0);
124+
maxobj = PyTuple_GET_ITEM(limits, 1);
112125
#if !defined(HAVE_LARGEFILE_SUPPORT)
113126
rl_out->rlim_cur = PyLong_AsLong(curobj);
114127
if (rl_out->rlim_cur == (rlim_t)-1 && PyErr_Occurred())
115-
return -1;
128+
goto error;
116129
rl_out->rlim_max = PyLong_AsLong(maxobj);
117130
if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())
118-
return -1;
131+
goto error;
119132
#else
120133
/* The limits are probably bigger than a long */
121134
rl_out->rlim_cur = PyLong_AsLongLong(curobj);
122135
if (rl_out->rlim_cur == (rlim_t)-1 && PyErr_Occurred())
123-
return -1;
136+
goto error;
124137
rl_out->rlim_max = PyLong_AsLongLong(maxobj);
125138
if (rl_out->rlim_max == (rlim_t)-1 && PyErr_Occurred())
126-
return -1;
139+
goto error;
127140
#endif
128141

142+
Py_DECREF(limits);
129143
rl_out->rlim_cur = rl_out->rlim_cur & RLIM_INFINITY;
130144
rl_out->rlim_max = rl_out->rlim_max & RLIM_INFINITY;
131145
return 0;
132146

147+
error:
148+
Py_DECREF(limits);
149+
return -1;
133150
}
134151

135152
static PyObject*
@@ -170,7 +187,7 @@ resource_setrlimit(PyObject *self, PyObject *args)
170187
{
171188
struct rlimit rl;
172189
int resource;
173-
PyObject *limits, *curobj, *maxobj;
190+
PyObject *limits;
174191

175192
if (!PyArg_ParseTuple(args, "iO:setrlimit", &resource, &limits))
176193
return NULL;
@@ -181,21 +198,8 @@ resource_setrlimit(PyObject *self, PyObject *args)
181198
return NULL;
182199
}
183200

184-
limits = PySequence_Tuple(limits);
185-
if (!limits)
186-
/* Here limits is a borrowed reference */
201+
if (py2rlimit(limits, &rl) < 0) {
187202
return NULL;
188-
189-
if (PyTuple_GET_SIZE(limits) != 2) {
190-
PyErr_SetString(PyExc_ValueError,
191-
"expected a tuple of 2 integers");
192-
goto error;
193-
}
194-
curobj = PyTuple_GET_ITEM(limits, 0);
195-
maxobj = PyTuple_GET_ITEM(limits, 1);
196-
197-
if (py2rlimit(curobj, maxobj, &rl) < 0) {
198-
goto error;
199203
}
200204

201205
if (setrlimit(resource, &rl) == -1) {
@@ -207,15 +211,9 @@ resource_setrlimit(PyObject *self, PyObject *args)
207211
"not allowed to raise maximum limit");
208212
else
209213
PyErr_SetFromErrno(PyExc_OSError);
210-
goto error;
214+
return NULL;
211215
}
212-
Py_DECREF(limits);
213-
Py_INCREF(Py_None);
214-
return Py_None;
215-
216-
error:
217-
Py_DECREF(limits);
218-
return NULL;
216+
Py_RETURN_NONE;
219217
}
220218

221219
#ifdef HAVE_PRLIMIT
@@ -225,10 +223,10 @@ resource_prlimit(PyObject *self, PyObject *args)
225223
struct rlimit old_limit, new_limit;
226224
int resource, retval;
227225
pid_t pid;
228-
PyObject *curobj=NULL, *maxobj=NULL;
226+
PyObject *limits = NULL;
229227

230-
if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i|(OO):prlimit",
231-
&pid, &resource, &curobj, &maxobj))
228+
if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i|O:prlimit",
229+
&pid, &resource, &limits))
232230
return NULL;
233231

234232
if (resource < 0 || resource >= RLIM_NLIMITS) {
@@ -237,8 +235,8 @@ resource_prlimit(PyObject *self, PyObject *args)
237235
return NULL;
238236
}
239237

240-
if (curobj != NULL) {
241-
if (py2rlimit(curobj, maxobj, &new_limit) < 0) {
238+
if (limits != NULL) {
239+
if (py2rlimit(limits, &new_limit) < 0) {
242240
return NULL;
243241
}
244242
retval = prlimit(pid, resource, &new_limit, &old_limit);

0 commit comments

Comments
 (0)