summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikita Sobolev <mail@sobolevn.me>2024-02-04 19:16:43 (GMT)
committerGitHub <noreply@github.com>2024-02-04 19:16:43 (GMT)
commit929d44e15a5667151beadb2d3a2528cd641639d6 (patch)
tree31c14abe2cafaf3ac27a22f7298f456668fed6ee
parentda8f9fb2ea65cc2784c2400fc39ad8c800a67a42 (diff)
downloadcpython-929d44e15a5667151beadb2d3a2528cd641639d6.zip
cpython-929d44e15a5667151beadb2d3a2528cd641639d6.tar.gz
cpython-929d44e15a5667151beadb2d3a2528cd641639d6.tar.bz2
gh-114685: PyBuffer_FillInfo() now raises on PyBUF_{READ,WRITE} (GH-114802)
-rw-r--r--Lib/test/test_buffer.py21
-rw-r--r--Misc/NEWS.d/next/C API/2024-01-31-15-43-35.gh-issue-114685.n7aRmX.rst3
-rw-r--r--Modules/_testcapimodule.c21
-rw-r--r--Objects/abstract.c16
4 files changed, 56 insertions, 5 deletions
diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py
index 535b795..5b1b95b 100644
--- a/Lib/test/test_buffer.py
+++ b/Lib/test/test_buffer.py
@@ -4591,6 +4591,27 @@ class TestPythonBufferProtocol(unittest.TestCase):
self.assertRaises(SystemError, buf.__buffer__, PyBUF_READ)
self.assertRaises(SystemError, buf.__buffer__, PyBUF_WRITE)
+ @unittest.skipIf(_testcapi is None, "requires _testcapi")
+ def test_c_fill_buffer_invalid_flags(self):
+ # PyBuffer_FillInfo
+ source = b"abc"
+ self.assertRaises(SystemError, _testcapi.buffer_fill_info,
+ source, 0, PyBUF_READ)
+ self.assertRaises(SystemError, _testcapi.buffer_fill_info,
+ source, 0, PyBUF_WRITE)
+
+ @unittest.skipIf(_testcapi is None, "requires _testcapi")
+ def test_c_fill_buffer_readonly_and_writable(self):
+ source = b"abc"
+ with _testcapi.buffer_fill_info(source, 1, PyBUF_SIMPLE) as m:
+ self.assertEqual(bytes(m), b"abc")
+ self.assertTrue(m.readonly)
+ with _testcapi.buffer_fill_info(source, 0, PyBUF_WRITABLE) as m:
+ self.assertEqual(bytes(m), b"abc")
+ self.assertFalse(m.readonly)
+ self.assertRaises(BufferError, _testcapi.buffer_fill_info,
+ source, 1, PyBUF_WRITABLE)
+
def test_inheritance(self):
class A(bytearray):
def __buffer__(self, flags):
diff --git a/Misc/NEWS.d/next/C API/2024-01-31-15-43-35.gh-issue-114685.n7aRmX.rst b/Misc/NEWS.d/next/C API/2024-01-31-15-43-35.gh-issue-114685.n7aRmX.rst
new file mode 100644
index 0000000..76ff006
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2024-01-31-15-43-35.gh-issue-114685.n7aRmX.rst
@@ -0,0 +1,3 @@
+:c:func:`PyBuffer_FillInfo` now raises a :exc:`SystemError` if called with
+:c:macro:`PyBUF_READ` or :c:macro:`PyBUF_WRITE` as flags. These flags should
+only be used with the ``PyMemoryView_*`` C API.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 6def680..e67de3e 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -1262,6 +1262,26 @@ make_memoryview_from_NULL_pointer(PyObject *self, PyObject *Py_UNUSED(ignored))
}
static PyObject *
+buffer_fill_info(PyObject *self, PyObject *args)
+{
+ Py_buffer info;
+ const char *data;
+ Py_ssize_t size;
+ int readonly;
+ int flags;
+
+ if (!PyArg_ParseTuple(args, "s#ii:buffer_fill_info",
+ &data, &size, &readonly, &flags)) {
+ return NULL;
+ }
+
+ if (PyBuffer_FillInfo(&info, NULL, (void *)data, size, readonly, flags) < 0) {
+ return NULL;
+ }
+ return PyMemoryView_FromBuffer(&info);
+}
+
+static PyObject *
test_from_contiguous(PyObject* self, PyObject *Py_UNUSED(ignored))
{
int data[9] = {-1,-1,-1,-1,-1,-1,-1,-1,-1};
@@ -3314,6 +3334,7 @@ static PyMethodDef TestMethods[] = {
{"eval_code_ex", eval_eval_code_ex, METH_VARARGS},
{"make_memoryview_from_NULL_pointer", make_memoryview_from_NULL_pointer,
METH_NOARGS},
+ {"buffer_fill_info", buffer_fill_info, METH_VARARGS},
{"crash_no_current_thread", crash_no_current_thread, METH_NOARGS},
{"test_current_tstate_matches", test_current_tstate_matches, METH_NOARGS},
{"run_in_subinterp", run_in_subinterp, METH_VARARGS},
diff --git a/Objects/abstract.c b/Objects/abstract.c
index daf04eb..07d4b89 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -767,11 +767,17 @@ PyBuffer_FillInfo(Py_buffer *view, PyObject *obj, void *buf, Py_ssize_t len,
return -1;
}
- if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) &&
- (readonly == 1)) {
- PyErr_SetString(PyExc_BufferError,
- "Object is not writable.");
- return -1;
+ if (flags != PyBUF_SIMPLE) { /* fast path */
+ if (flags == PyBUF_READ || flags == PyBUF_WRITE) {
+ PyErr_BadInternalCall();
+ return -1;
+ }
+ if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) &&
+ (readonly == 1)) {
+ PyErr_SetString(PyExc_BufferError,
+ "Object is not writable.");
+ return -1;
+ }
}
view->obj = Py_XNewRef(obj);