Skip to content

Commit 8d6c62d

Browse files
committed
check possible recursive _as_parameter_ to prevent segfault (closes #1838)
1 parent b8a5769 commit 8d6c62d

5 files changed

Lines changed: 43 additions & 2 deletions

File tree

Lib/ctypes/test/test_as_parameter.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,18 @@ class S8I(Structure):
187187
self.assertEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
188188
(9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))
189189

190+
def test_recursive_as_param(self):
191+
from ctypes import c_int
192+
193+
class A(object):
194+
pass
195+
196+
a = A()
197+
a._as_parameter_ = a
198+
with self.assertRaises(RuntimeError):
199+
c_int.from_param(a)
200+
201+
190202
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
191203

192204
class AsParamWrapper(object):

Lib/lib2to3/refactor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ def traverse_by(self, fixers, traversal):
500500
node = new
501501

502502
def processed_file(self, new_text, filename, old_text=None, write=False,
503-
encoding=None):
503+
encoding=None, newlines=None):
504504
"""
505505
Called when a file has been refactored, and there are changes.
506506
"""

Lib/lib2to3/tests/test_refactor.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,23 @@ def mock_refactor_file(self, f, *args):
231231
os.path.join("a_dir", "stuff.py")]
232232
check(tree, tree)
233233

234+
def test_preserve_file_newlines(self):
235+
rt = self.rt(fixers=_2TO3_FIXERS)
236+
for nl in ("\r\n", "\n"):
237+
data = "print y%s%syes%sok%s" % ((nl,) * 4)
238+
handle, tmp = tempfile.mkstemp()
239+
os.close(handle)
240+
try:
241+
with open(tmp, "w") as fp:
242+
fp.write(data)
243+
rt.refactor_file(tmp)
244+
with open(tmp, "r") as fp:
245+
contents = fp.read()
246+
finally:
247+
os.unlink(tmp)
248+
for line in contents.splitlines(True):
249+
self.assertTrue(line.endswith(nl))
250+
234251
def test_file_encoding(self):
235252
fn = os.path.join(TEST_DATA_DIR, "different_encoding.py")
236253
self.check_file_refactoring(fn)

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,9 @@ Library
238238
Extensions
239239
----------
240240

241+
- Issue #1838: Prevent segfault in ctypes, when _as_parameter_ on a class is set
242+
to an instance of the class.
243+
241244
- Issue #678250: Make mmap flush a noop on ACCESS_READ and ACCESS_COPY.
242245

243246
Build

Modules/_ctypes/_ctypes.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2004,10 +2004,14 @@ PyCSimpleType_from_param(PyObject *type, PyObject *value)
20042004
PyCArgObject *parg;
20052005
struct fielddesc *fd;
20062006
PyObject *as_parameter;
2007+
int res;
20072008

20082009
/* If the value is already an instance of the requested type,
20092010
we can use it as is */
2010-
if (1 == PyObject_IsInstance(value, type)) {
2011+
res = PyObject_IsInstance(value, type);
2012+
if (res == -1)
2013+
return NULL;
2014+
if (res) {
20112015
Py_INCREF(value);
20122016
return value;
20132017
}
@@ -2036,7 +2040,12 @@ PyCSimpleType_from_param(PyObject *type, PyObject *value)
20362040

20372041
as_parameter = PyObject_GetAttrString(value, "_as_parameter_");
20382042
if (as_parameter) {
2043+
if (Py_EnterRecursiveCall("while processing _as_parameter_")) {
2044+
Py_DECREF(as_parameter);
2045+
return NULL;
2046+
}
20392047
value = PyCSimpleType_from_param(type, as_parameter);
2048+
Py_LeaveRecursiveCall();
20402049
Py_DECREF(as_parameter);
20412050
return value;
20422051
}

0 commit comments

Comments
 (0)