diff --git a/Lib/test/test_ctypes/test_frombuffer.py b/Lib/test/test_ctypes/test_frombuffer.py index d4e161f864d4098..a5b34a11fef303c 100644 --- a/Lib/test/test_ctypes/test_frombuffer.py +++ b/Lib/test/test_ctypes/test_frombuffer.py @@ -124,6 +124,25 @@ def test_from_buffer_copy_with_offset(self): with self.assertRaises(ValueError): (c_int * 1).from_buffer_copy(a, 16 * sizeof(c_int)) + def test_from_buffer_b_base_with_ctypes_source(self): + class Inner(Structure): + _fields_ = [("x", c_int)] + + class Outer(Structure): + _fields_ = [("inner", Inner), ("y", c_int)] + + buf = bytearray(sizeof(Outer)) + outer = Outer.from_buffer(buf) + inner = Inner.from_buffer(outer, 0) + + self.assertIs(inner._b_base_, outer) + + def test_from_buffer_b_base_with_non_ctypes_source(self): + buf = bytearray(sizeof(c_int)) + x = c_int.from_buffer(buf) + + self.assertIsNone(x._b_base_) + def test_abstract(self): self.assertRaises(TypeError, Array.from_buffer, bytearray(10)) self.assertRaises(TypeError, Structure.from_buffer, bytearray(10)) diff --git a/Misc/NEWS.d/next/Library/2026-06-30-21-16-45.gh-issue-135894.bBmV3U.rst b/Misc/NEWS.d/next/Library/2026-06-30-21-16-45.gh-issue-135894.bBmV3U.rst new file mode 100644 index 000000000000000..8c4ddd5e9ab139c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-30-21-16-45.gh-issue-135894.bBmV3U.rst @@ -0,0 +1,2 @@ +:meth:`~ctypes._CData.from_buffer` now sets :attr:`~ctypes._CData._b_base_` +when the source is a ctypes object. diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index e891249668c20f5..762e584a83596b0 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -919,6 +919,10 @@ CDataType_from_buffer_impl(PyObject *type, PyTypeObject *cls, PyObject *obj, return NULL; } + if (CDataObject_Check(st, obj)) { + ((CDataObject *)result)->b_base = (CDataObject *)Py_NewRef(obj); + } + return result; }