mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Issue #25498: Merge ctypes crash fix from 3.4 into 3.5
This commit is contained in:
commit
0da4ac1f21
4 changed files with 72 additions and 20 deletions
|
@ -38,11 +38,32 @@ class Test(unittest.TestCase):
|
||||||
del a; gc.collect(); gc.collect(); gc.collect()
|
del a; gc.collect(); gc.collect(); gc.collect()
|
||||||
self.assertEqual(x[:], expected)
|
self.assertEqual(x[:], expected)
|
||||||
|
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaisesRegex(TypeError, "not writable"):
|
||||||
(c_char * 16).from_buffer(b"a" * 16)
|
(c_char * 16).from_buffer(b"a" * 16)
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaisesRegex(TypeError, "not writable"):
|
||||||
|
(c_char * 16).from_buffer(memoryview(b"a" * 16))
|
||||||
|
with self.assertRaisesRegex(TypeError, "not C contiguous"):
|
||||||
|
(c_char * 16).from_buffer(memoryview(bytearray(b"a" * 16))[::-1])
|
||||||
|
msg = "does not have the buffer interface"
|
||||||
|
with self.assertRaisesRegex(TypeError, msg):
|
||||||
(c_char * 16).from_buffer("a" * 16)
|
(c_char * 16).from_buffer("a" * 16)
|
||||||
|
|
||||||
|
def test_fortran_contiguous(self):
|
||||||
|
try:
|
||||||
|
import _testbuffer
|
||||||
|
except ImportError as err:
|
||||||
|
self.skipTest(str(err))
|
||||||
|
flags = _testbuffer.ND_WRITABLE | _testbuffer.ND_FORTRAN
|
||||||
|
array = _testbuffer.ndarray(
|
||||||
|
[97] * 16, format="B", shape=[4, 4], flags=flags)
|
||||||
|
with self.assertRaisesRegex(TypeError, "not C contiguous"):
|
||||||
|
(c_char * 16).from_buffer(array)
|
||||||
|
array = memoryview(array)
|
||||||
|
self.assertTrue(array.f_contiguous)
|
||||||
|
self.assertFalse(array.c_contiguous)
|
||||||
|
with self.assertRaisesRegex(TypeError, "not C contiguous"):
|
||||||
|
(c_char * 16).from_buffer(array)
|
||||||
|
|
||||||
def test_from_buffer_with_offset(self):
|
def test_from_buffer_with_offset(self):
|
||||||
a = array.array("i", range(16))
|
a = array.array("i", range(16))
|
||||||
x = (c_int * 15).from_buffer(a, sizeof(c_int))
|
x = (c_int * 15).from_buffer(a, sizeof(c_int))
|
||||||
|
@ -55,6 +76,12 @@ class Test(unittest.TestCase):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
(c_int * 1).from_buffer(a, 16 * sizeof(c_int))
|
(c_int * 1).from_buffer(a, 16 * sizeof(c_int))
|
||||||
|
|
||||||
|
def test_from_buffer_memoryview(self):
|
||||||
|
a = [c_char.from_buffer(memoryview(bytearray(b'a')))]
|
||||||
|
a.append(a)
|
||||||
|
del a
|
||||||
|
gc.collect() # Should not crash
|
||||||
|
|
||||||
def test_from_buffer_copy(self):
|
def test_from_buffer_copy(self):
|
||||||
a = array.array("i", range(16))
|
a = array.array("i", range(16))
|
||||||
x = (c_int * 16).from_buffer_copy(a)
|
x = (c_int * 16).from_buffer_copy(a)
|
||||||
|
|
|
@ -398,6 +398,7 @@ Gökcen Eraslan
|
||||||
Stoffel Erasmus
|
Stoffel Erasmus
|
||||||
Jürgen A. Erhard
|
Jürgen A. Erhard
|
||||||
Michael Ernst
|
Michael Ernst
|
||||||
|
Eryksun
|
||||||
Ben Escoto
|
Ben Escoto
|
||||||
Andy Eskilsson
|
Andy Eskilsson
|
||||||
André Espaze
|
André Espaze
|
||||||
|
|
|
@ -67,6 +67,10 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #25498: Fix a crash when garbage-collecting ctypes objects created
|
||||||
|
by wrapping a memoryview. This was a regression made in 3.5a1. Based
|
||||||
|
on patch by Eryksun.
|
||||||
|
|
||||||
- Issue #25584: Added "escape" to the __all__ list in the glob module.
|
- Issue #25584: Added "escape" to the __all__ list in the glob module.
|
||||||
|
|
||||||
- Issue #25584: Fixed recursive glob() with patterns starting with '\*\*'.
|
- Issue #25584: Fixed recursive glob() with patterns starting with '\*\*'.
|
||||||
|
|
|
@ -463,45 +463,65 @@ KeepRef(CDataObject *target, Py_ssize_t index, PyObject *keep);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
CDataType_from_buffer(PyObject *type, PyObject *args)
|
CDataType_from_buffer(PyObject *type, PyObject *args)
|
||||||
{
|
{
|
||||||
Py_buffer buffer;
|
PyObject *obj;
|
||||||
|
PyObject *mv;
|
||||||
|
PyObject *result;
|
||||||
|
Py_buffer *buffer;
|
||||||
Py_ssize_t offset = 0;
|
Py_ssize_t offset = 0;
|
||||||
PyObject *result, *mv;
|
|
||||||
StgDictObject *dict = PyType_stgdict(type);
|
StgDictObject *dict = PyType_stgdict(type);
|
||||||
assert (dict);
|
assert (dict);
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "w*|n:from_buffer", &buffer, &offset))
|
if (!PyArg_ParseTuple(args, "O|n:from_buffer", &obj, &offset))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
mv = PyMemoryView_FromObject(obj);
|
||||||
|
if (mv == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
buffer = PyMemoryView_GET_BUFFER(mv);
|
||||||
|
|
||||||
|
if (buffer->readonly) {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"underlying buffer is not writable");
|
||||||
|
Py_DECREF(mv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PyBuffer_IsContiguous(buffer, 'C')) {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"underlying buffer is not C contiguous");
|
||||||
|
Py_DECREF(mv);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"offset cannot be negative");
|
"offset cannot be negative");
|
||||||
PyBuffer_Release(&buffer);
|
Py_DECREF(mv);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (dict->size > buffer.len - offset) {
|
|
||||||
|
if (dict->size > buffer->len - offset) {
|
||||||
PyErr_Format(PyExc_ValueError,
|
PyErr_Format(PyExc_ValueError,
|
||||||
"Buffer size too small (%zd instead of at least %zd bytes)",
|
"Buffer size too small "
|
||||||
buffer.len, dict->size + offset);
|
"(%zd instead of at least %zd bytes)",
|
||||||
PyBuffer_Release(&buffer);
|
buffer->len, dict->size + offset);
|
||||||
|
Py_DECREF(mv);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = PyCData_AtAddress(type, (char *)buffer.buf + offset);
|
result = PyCData_AtAddress(type, (char *)buffer->buf + offset);
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
PyBuffer_Release(&buffer);
|
Py_DECREF(mv);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mv = PyMemoryView_FromBuffer(&buffer);
|
if (-1 == KeepRef((CDataObject *)result, -1, mv)) {
|
||||||
if (mv == NULL) {
|
Py_DECREF(result);
|
||||||
PyBuffer_Release(&buffer);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* Hack the memoryview so that it will release the buffer. */
|
|
||||||
((PyMemoryViewObject *)mv)->mbuf->master.obj = buffer.obj;
|
|
||||||
((PyMemoryViewObject *)mv)->view.obj = buffer.obj;
|
|
||||||
if (-1 == KeepRef((CDataObject *)result, -1, mv))
|
|
||||||
result = NULL;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue