mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Issue #6083: Fix multiple segmentation faults occured when PyArg_ParseTuple
parses nested mutating sequence.
This commit is contained in:
parent
f727c31133
commit
a07a8b4f18
7 changed files with 116 additions and 15 deletions
|
@ -31,5 +31,33 @@ class ReturnFuncPtrTestCase(unittest.TestCase):
|
||||||
self.assertRaises(ArgumentError, strchr, "abcdef", 3)
|
self.assertRaises(ArgumentError, strchr, "abcdef", 3)
|
||||||
self.assertRaises(TypeError, strchr, "abcdef")
|
self.assertRaises(TypeError, strchr, "abcdef")
|
||||||
|
|
||||||
|
def test_from_dll(self):
|
||||||
|
dll = CDLL(_ctypes_test.__file__)
|
||||||
|
# _CFuncPtr instances are now callable with a tuple argument
|
||||||
|
# which denotes a function name and a dll:
|
||||||
|
strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(("strchr", dll))
|
||||||
|
self.assertTrue(strchr(b"abcdef", b"b"), "bcdef")
|
||||||
|
self.assertEqual(strchr(b"abcdef", b"x"), None)
|
||||||
|
self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
|
||||||
|
self.assertRaises(TypeError, strchr, b"abcdef")
|
||||||
|
|
||||||
|
# Issue 6083: Reference counting bug
|
||||||
|
def test_test_from_dll_refcount(self):
|
||||||
|
class BadSequence(tuple):
|
||||||
|
def __getitem__(self, key):
|
||||||
|
if key == 0:
|
||||||
|
return "strchr"
|
||||||
|
if key == 1:
|
||||||
|
return CDLL(_ctypes_test.__file__)
|
||||||
|
raise IndexError
|
||||||
|
|
||||||
|
# _CFuncPtr instances are now callable with a tuple argument
|
||||||
|
# which denotes a function name and a dll:
|
||||||
|
strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(BadSequence(("strchr", CDLL(_ctypes_test.__file__))))
|
||||||
|
self.assertTrue(strchr(b"abcdef", b"b"), "bcdef")
|
||||||
|
self.assertEqual(strchr(b"abcdef", b"x"), None)
|
||||||
|
self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0)
|
||||||
|
self.assertRaises(TypeError, strchr, b"abcdef")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -151,6 +151,23 @@ class TestPartial(unittest.TestCase):
|
||||||
f_copy = pickle.loads(pickle.dumps(f))
|
f_copy = pickle.loads(pickle.dumps(f))
|
||||||
self.assertEqual(signature(f), signature(f_copy))
|
self.assertEqual(signature(f), signature(f_copy))
|
||||||
|
|
||||||
|
# Issue 6083: Reference counting bug
|
||||||
|
def test_setstate_refcount(self):
|
||||||
|
class BadSequence:
|
||||||
|
def __len__(self):
|
||||||
|
return 4
|
||||||
|
def __getitem__(self, key):
|
||||||
|
if key == 0:
|
||||||
|
return max
|
||||||
|
elif key == 1:
|
||||||
|
return tuple(range(1000000))
|
||||||
|
elif key in (2, 3):
|
||||||
|
return {}
|
||||||
|
raise IndexError
|
||||||
|
|
||||||
|
f = self.thetype(object)
|
||||||
|
self.assertRaises(SystemError, f.__setstate__, BadSequence())
|
||||||
|
|
||||||
class PartialSubclass(functools.partial):
|
class PartialSubclass(functools.partial):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -164,6 +181,7 @@ class TestPythonPartial(TestPartial):
|
||||||
|
|
||||||
# the python version isn't picklable
|
# the python version isn't picklable
|
||||||
def test_pickle(self): pass
|
def test_pickle(self): pass
|
||||||
|
def test_setstate_refcount(self): pass
|
||||||
|
|
||||||
class TestUpdateWrapper(unittest.TestCase):
|
class TestUpdateWrapper(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,23 @@ class ResourceTest(unittest.TestCase):
|
||||||
except (ValueError, AttributeError):
|
except (ValueError, AttributeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Issue 6083: Reference counting bug
|
||||||
|
def test_setrusage_refcount(self):
|
||||||
|
try:
|
||||||
|
limits = resource.getrlimit(resource.RLIMIT_CPU)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
class BadSequence:
|
||||||
|
def __len__(self):
|
||||||
|
return 2
|
||||||
|
def __getitem__(self, key):
|
||||||
|
if key in (0, 1):
|
||||||
|
return len(tuple(range(1000000)))
|
||||||
|
raise IndexError
|
||||||
|
|
||||||
|
resource.setrlimit(resource.RLIMIT_CPU, BadSequence())
|
||||||
|
|
||||||
def test_main(verbose=None):
|
def test_main(verbose=None):
|
||||||
test_support.run_unittest(ResourceTest)
|
test_support.run_unittest(ResourceTest)
|
||||||
|
|
||||||
|
|
|
@ -199,6 +199,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #6083: Fix multiple segmentation faults occured when PyArg_ParseTuple
|
||||||
|
parses nested mutating sequence.
|
||||||
|
|
||||||
- Issue #5289: Fix ctypes.util.find_library on Solaris.
|
- Issue #5289: Fix ctypes.util.find_library on Solaris.
|
||||||
|
|
||||||
- Issue #17106: Fix a segmentation fault in io.TextIOWrapper when an underlying
|
- Issue #17106: Fix a segmentation fault in io.TextIOWrapper when an underlying
|
||||||
|
|
|
@ -3294,23 +3294,37 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
int (* address)(void);
|
int (* address)(void);
|
||||||
|
PyObject *ftuple;
|
||||||
PyObject *dll;
|
PyObject *dll;
|
||||||
PyObject *obj;
|
PyObject *obj;
|
||||||
PyCFuncPtrObject *self;
|
PyCFuncPtrObject *self;
|
||||||
void *handle;
|
void *handle;
|
||||||
PyObject *paramflags = NULL;
|
PyObject *paramflags = NULL;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "(O&O)|O", _get_name, &name, &dll, ¶mflags))
|
if (!PyArg_ParseTuple(args, "O|O", &ftuple, ¶mflags))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (paramflags == Py_None)
|
if (paramflags == Py_None)
|
||||||
paramflags = NULL;
|
paramflags = NULL;
|
||||||
|
|
||||||
obj = PyObject_GetAttrString(dll, "_handle");
|
ftuple = PySequence_Tuple(ftuple);
|
||||||
if (!obj)
|
if (!ftuple)
|
||||||
|
/* Here ftuple is a borrowed reference */
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(ftuple, "O&O", _get_name, &name, &dll)) {
|
||||||
|
Py_DECREF(ftuple);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = PyObject_GetAttrString(dll, "_handle");
|
||||||
|
if (!obj) {
|
||||||
|
Py_DECREF(ftuple);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
if (!PyInt_Check(obj) && !PyLong_Check(obj)) {
|
if (!PyInt_Check(obj) && !PyLong_Check(obj)) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"the _handle attribute of the second argument must be an integer");
|
"the _handle attribute of the second argument must be an integer");
|
||||||
|
Py_DECREF(ftuple);
|
||||||
Py_DECREF(obj);
|
Py_DECREF(obj);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -3319,6 +3333,7 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"could not convert the _handle attribute to a pointer");
|
"could not convert the _handle attribute to a pointer");
|
||||||
|
Py_DECREF(ftuple);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3333,6 +3348,7 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
PyErr_Format(PyExc_AttributeError,
|
PyErr_Format(PyExc_AttributeError,
|
||||||
"function ordinal %d not found",
|
"function ordinal %d not found",
|
||||||
(WORD)(size_t)name);
|
(WORD)(size_t)name);
|
||||||
|
Py_DECREF(ftuple);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -3346,9 +3362,12 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
#else
|
#else
|
||||||
PyErr_SetString(PyExc_AttributeError, ctypes_dlerror());
|
PyErr_SetString(PyExc_AttributeError, ctypes_dlerror());
|
||||||
#endif
|
#endif
|
||||||
|
Py_DECREF(ftuple);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Py_INCREF(dll); /* for KeepRef */
|
||||||
|
Py_DECREF(ftuple);
|
||||||
if (!_validate_paramflags(type, paramflags))
|
if (!_validate_paramflags(type, paramflags))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -3361,7 +3380,6 @@ PyCFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
|
|
||||||
*(void **)self->b_ptr = address;
|
*(void **)self->b_ptr = address;
|
||||||
|
|
||||||
Py_INCREF((PyObject *)dll); /* for KeepRef */
|
|
||||||
if (-1 == KeepRef((CDataObject *)self, 0, dll)) {
|
if (-1 == KeepRef((CDataObject *)self, 0, dll)) {
|
||||||
Py_DECREF((PyObject *)self);
|
Py_DECREF((PyObject *)self);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -290,10 +290,10 @@ partial_reduce(partialobject *pto, PyObject *unused)
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
partial_setstate(partialobject *pto, PyObject *args)
|
partial_setstate(partialobject *pto, PyObject *state)
|
||||||
{
|
{
|
||||||
PyObject *fn, *fnargs, *kw, *dict;
|
PyObject *fn, *fnargs, *kw, *dict;
|
||||||
if (!PyArg_ParseTuple(args, "(OOOO):__setstate__",
|
if (!PyArg_ParseTuple(state, "OOOO",
|
||||||
&fn, &fnargs, &kw, &dict))
|
&fn, &fnargs, &kw, &dict))
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_XDECREF(pto->fn);
|
Py_XDECREF(pto->fn);
|
||||||
|
@ -317,7 +317,7 @@ partial_setstate(partialobject *pto, PyObject *args)
|
||||||
|
|
||||||
static PyMethodDef partial_methods[] = {
|
static PyMethodDef partial_methods[] = {
|
||||||
{"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
|
{"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
|
||||||
{"__setstate__", (PyCFunction)partial_setstate, METH_VARARGS},
|
{"__setstate__", (PyCFunction)partial_setstate, METH_O},
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -145,10 +145,9 @@ resource_setrlimit(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
struct rlimit rl;
|
struct rlimit rl;
|
||||||
int resource;
|
int resource;
|
||||||
PyObject *curobj, *maxobj;
|
PyObject *limits, *curobj, *maxobj;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i(OO):setrlimit",
|
if (!PyArg_ParseTuple(args, "iO:setrlimit", &resource, &limits))
|
||||||
&resource, &curobj, &maxobj))
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (resource < 0 || resource >= RLIM_NLIMITS) {
|
if (resource < 0 || resource >= RLIM_NLIMITS) {
|
||||||
|
@ -157,23 +156,36 @@ resource_setrlimit(PyObject *self, PyObject *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
limits = PySequence_Tuple(limits);
|
||||||
|
if (!limits)
|
||||||
|
/* Here limits is a borrowed reference */
|
||||||
|
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 !defined(HAVE_LARGEFILE_SUPPORT)
|
#if !defined(HAVE_LARGEFILE_SUPPORT)
|
||||||
rl.rlim_cur = PyInt_AsLong(curobj);
|
rl.rlim_cur = PyInt_AsLong(curobj);
|
||||||
if (rl.rlim_cur == (rlim_t)-1 && PyErr_Occurred())
|
if (rl.rlim_cur == (rlim_t)-1 && PyErr_Occurred())
|
||||||
return NULL;
|
goto error;
|
||||||
rl.rlim_max = PyInt_AsLong(maxobj);
|
rl.rlim_max = PyInt_AsLong(maxobj);
|
||||||
if (rl.rlim_max == (rlim_t)-1 && PyErr_Occurred())
|
if (rl.rlim_max == (rlim_t)-1 && PyErr_Occurred())
|
||||||
return NULL;
|
goto error;
|
||||||
#else
|
#else
|
||||||
/* The limits are probably bigger than a long */
|
/* The limits are probably bigger than a long */
|
||||||
rl.rlim_cur = PyLong_Check(curobj) ?
|
rl.rlim_cur = PyLong_Check(curobj) ?
|
||||||
PyLong_AsLongLong(curobj) : PyInt_AsLong(curobj);
|
PyLong_AsLongLong(curobj) : PyInt_AsLong(curobj);
|
||||||
if (rl.rlim_cur == (rlim_t)-1 && PyErr_Occurred())
|
if (rl.rlim_cur == (rlim_t)-1 && PyErr_Occurred())
|
||||||
return NULL;
|
goto error;
|
||||||
rl.rlim_max = PyLong_Check(maxobj) ?
|
rl.rlim_max = PyLong_Check(maxobj) ?
|
||||||
PyLong_AsLongLong(maxobj) : PyInt_AsLong(maxobj);
|
PyLong_AsLongLong(maxobj) : PyInt_AsLong(maxobj);
|
||||||
if (rl.rlim_max == (rlim_t)-1 && PyErr_Occurred())
|
if (rl.rlim_max == (rlim_t)-1 && PyErr_Occurred())
|
||||||
return NULL;
|
goto error;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rl.rlim_cur = rl.rlim_cur & RLIM_INFINITY;
|
rl.rlim_cur = rl.rlim_cur & RLIM_INFINITY;
|
||||||
|
@ -187,10 +199,15 @@ resource_setrlimit(PyObject *self, PyObject *args)
|
||||||
"not allowed to raise maximum limit");
|
"not allowed to raise maximum limit");
|
||||||
else
|
else
|
||||||
PyErr_SetFromErrno(ResourceError);
|
PyErr_SetFromErrno(ResourceError);
|
||||||
return NULL;
|
goto error;
|
||||||
}
|
}
|
||||||
|
Py_DECREF(limits);
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_DECREF(limits);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue