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

Skip to content

Commit b94eef2

Browse files
Issue #20191: Fixed a crash in resource.prlimit() when pass a sequence that
doesn't own its elements as limits.
1 parent 4ec1590 commit b94eef2

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
@@ -130,6 +130,9 @@ Core and Builtins
130130
Library
131131
-------
132132

133+
- Issue #20191: Fixed a crash in resource.prlimit() when pass a sequence that
134+
doesn't own its elements as limits.
135+
133136
- Issue #28779: multiprocessing.set_forkserver_preload() would crash the
134137
forkserver process if a preloaded module instantiated some
135138
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*
@@ -172,7 +189,7 @@ resource_setrlimit(PyObject *self, PyObject *args)
172189
{
173190
struct rlimit rl;
174191
int resource;
175-
PyObject *limits, *curobj, *maxobj;
192+
PyObject *limits;
176193

177194
if (!PyArg_ParseTuple(args, "iO:setrlimit", &resource, &limits))
178195
return NULL;
@@ -183,21 +200,8 @@ resource_setrlimit(PyObject *self, PyObject *args)
183200
return NULL;
184201
}
185202

186-
limits = PySequence_Tuple(limits);
187-
if (!limits)
188-
/* Here limits is a borrowed reference */
203+
if (py2rlimit(limits, &rl) < 0) {
189204
return NULL;
190-
191-
if (PyTuple_GET_SIZE(limits) != 2) {
192-
PyErr_SetString(PyExc_ValueError,
193-
"expected a tuple of 2 integers");
194-
goto error;
195-
}
196-
curobj = PyTuple_GET_ITEM(limits, 0);
197-
maxobj = PyTuple_GET_ITEM(limits, 1);
198-
199-
if (py2rlimit(curobj, maxobj, &rl) < 0) {
200-
goto error;
201205
}
202206

203207
if (setrlimit(resource, &rl) == -1) {
@@ -209,15 +213,9 @@ resource_setrlimit(PyObject *self, PyObject *args)
209213
"not allowed to raise maximum limit");
210214
else
211215
PyErr_SetFromErrno(PyExc_OSError);
212-
goto error;
216+
return NULL;
213217
}
214-
Py_DECREF(limits);
215-
Py_INCREF(Py_None);
216-
return Py_None;
217-
218-
error:
219-
Py_DECREF(limits);
220-
return NULL;
218+
Py_RETURN_NONE;
221219
}
222220

223221
#ifdef HAVE_PRLIMIT
@@ -227,10 +225,10 @@ resource_prlimit(PyObject *self, PyObject *args)
227225
struct rlimit old_limit, new_limit;
228226
int resource, retval;
229227
pid_t pid;
230-
PyObject *curobj=NULL, *maxobj=NULL;
228+
PyObject *limits = NULL;
231229

232-
if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i|(OO):prlimit",
233-
&pid, &resource, &curobj, &maxobj))
230+
if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i|O:prlimit",
231+
&pid, &resource, &limits))
234232
return NULL;
235233

236234
if (resource < 0 || resource >= RLIM_NLIMITS) {
@@ -239,8 +237,8 @@ resource_prlimit(PyObject *self, PyObject *args)
239237
return NULL;
240238
}
241239

242-
if (curobj != NULL) {
243-
if (py2rlimit(curobj, maxobj, &new_limit) < 0) {
240+
if (limits != NULL) {
241+
if (py2rlimit(limits, &new_limit) < 0) {
244242
return NULL;
245243
}
246244
retval = prlimit(pid, resource, &new_limit, &old_limit);

0 commit comments

Comments
 (0)