https://github.com/python/cpython/commit/606003ffa9e400cc22cc3b11f31118e2e24f688e commit: 606003ffa9e400cc22cc3b11f31118e2e24f688e branch: main author: Eric Snow <ericsnowcurren...@gmail.com> committer: ericsnowcurrently <ericsnowcurren...@gmail.com> date: 2025-04-28T12:52:36-06:00 summary:
gh-132775: Add _PyBytes_GetXIData() (gh-133101) This is the base for several other XIData wrappers, like pickle and marshal. It is essentially a refactor of the existing bytes XIData code. files: M Include/internal/pycore_crossinterp.h M Python/crossinterp.c M Python/crossinterp_data_lookup.h diff --git a/Include/internal/pycore_crossinterp.h b/Include/internal/pycore_crossinterp.h index 319b86186b1e69..5cf9f8fb5a0388 100644 --- a/Include/internal/pycore_crossinterp.h +++ b/Include/internal/pycore_crossinterp.h @@ -112,6 +112,8 @@ PyAPI_FUNC(void) _PyXIData_Clear(PyInterpreterState *, _PyXIData_t *); do { \ (DATA)->free = (FUNC); \ } while (0) +#define _PyXIData_CHECK_FREE(DATA, FUNC) \ + ((DATA)->free == (FUNC)) // Additionally, some shareable types are essentially light wrappers // around other shareable types. The xidatafunc of the wrapper // can often be implemented by calling the wrapped object's @@ -123,6 +125,8 @@ PyAPI_FUNC(void) _PyXIData_Clear(PyInterpreterState *, _PyXIData_t *); do { \ (DATA)->new_object = (FUNC); \ } while (0) +#define _PyXIData_CHECK_NEW_OBJECT(DATA, FUNC) \ + ((DATA)->new_object == (FUNC)) /* getting cross-interpreter data */ @@ -148,6 +152,25 @@ PyAPI_FUNC(int) _PyObject_GetXIData( PyObject *, _PyXIData_t *); +// _PyObject_GetXIData() for bytes +typedef struct { + const char *bytes; + Py_ssize_t len; +} _PyBytes_data_t; +PyAPI_FUNC(int) _PyBytes_GetData(PyObject *, _PyBytes_data_t *); +PyAPI_FUNC(PyObject *) _PyBytes_FromData(_PyBytes_data_t *); +PyAPI_FUNC(PyObject *) _PyBytes_FromXIData(_PyXIData_t *); +PyAPI_FUNC(int) _PyBytes_GetXIData( + PyThreadState *, + PyObject *, + _PyXIData_t *); +PyAPI_FUNC(_PyBytes_data_t *) _PyBytes_GetXIDataWrapped( + PyThreadState *, + PyObject *, + size_t, + xid_newobjfunc, + _PyXIData_t *); + /* using cross-interpreter data */ diff --git a/Python/crossinterp.c b/Python/crossinterp.c index a1dd6b5901dcfa..662c9c72b15eb7 100644 --- a/Python/crossinterp.c +++ b/Python/crossinterp.c @@ -154,7 +154,7 @@ _PyXIData_InitWithSize(_PyXIData_t *xidata, // where it was allocated, so the interpreter is required. assert(interp != NULL); _PyXIData_Init(xidata, interp, NULL, obj, new_object); - xidata->data = PyMem_RawMalloc(size); + xidata->data = PyMem_RawCalloc(1, size); if (xidata->data == NULL) { return -1; } diff --git a/Python/crossinterp_data_lookup.h b/Python/crossinterp_data_lookup.h index 6af208dcdd13c0..efef1e06d82f63 100644 --- a/Python/crossinterp_data_lookup.h +++ b/Python/crossinterp_data_lookup.h @@ -348,36 +348,98 @@ _PyXIData_UnregisterClass(PyThreadState *tstate, PyTypeObject *cls) // bytes -struct _shared_bytes_data { +int +_PyBytes_GetData(PyObject *obj, _PyBytes_data_t *data) +{ + if (!PyBytes_Check(obj)) { + PyErr_Format(PyExc_TypeError, "expected bytes, got %R", obj); + return -1; + } char *bytes; Py_ssize_t len; -}; + if (PyBytes_AsStringAndSize(obj, &bytes, &len) < 0) { + return -1; + } + *data = (_PyBytes_data_t){ + .bytes = bytes, + .len = len, + }; + return 0; +} -static PyObject * -_new_bytes_object(_PyXIData_t *xidata) +PyObject * +_PyBytes_FromData(_PyBytes_data_t *data) { - struct _shared_bytes_data *shared = (struct _shared_bytes_data *)(xidata->data); - return PyBytes_FromStringAndSize(shared->bytes, shared->len); + return PyBytes_FromStringAndSize(data->bytes, data->len); +} + +PyObject * +_PyBytes_FromXIData(_PyXIData_t *xidata) +{ + _PyBytes_data_t *data = (_PyBytes_data_t *)xidata->data; + assert(_PyXIData_OBJ(xidata) != NULL + && PyBytes_Check(_PyXIData_OBJ(xidata))); + return _PyBytes_FromData(data); } static int -_bytes_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *xidata) +_bytes_shared(PyThreadState *tstate, + PyObject *obj, size_t size, xid_newobjfunc newfunc, + _PyXIData_t *xidata) { + assert(size >= sizeof(_PyBytes_data_t)); + assert(newfunc != NULL); if (_PyXIData_InitWithSize( - xidata, tstate->interp, sizeof(struct _shared_bytes_data), obj, - _new_bytes_object - ) < 0) + xidata, tstate->interp, size, obj, newfunc) < 0) { return -1; } - struct _shared_bytes_data *shared = (struct _shared_bytes_data *)xidata->data; - if (PyBytes_AsStringAndSize(obj, &shared->bytes, &shared->len) < 0) { + _PyBytes_data_t *data = (_PyBytes_data_t *)xidata->data; + if (_PyBytes_GetData(obj, data) < 0) { _PyXIData_Clear(tstate->interp, xidata); return -1; } return 0; } +int +_PyBytes_GetXIData(PyThreadState *tstate, PyObject *obj, _PyXIData_t *xidata) +{ + if (!PyBytes_Check(obj)) { + PyErr_Format(PyExc_TypeError, "expected bytes, got %R", obj); + return -1; + } + size_t size = sizeof(_PyBytes_data_t); + return _bytes_shared(tstate, obj, size, _PyBytes_FromXIData, xidata); +} + +_PyBytes_data_t * +_PyBytes_GetXIDataWrapped(PyThreadState *tstate, + PyObject *obj, size_t size, xid_newobjfunc newfunc, + _PyXIData_t *xidata) +{ + if (!PyBytes_Check(obj)) { + PyErr_Format(PyExc_TypeError, "expected bytes, got %R", obj); + return NULL; + } + if (size < sizeof(_PyBytes_data_t)) { + PyErr_Format(PyExc_ValueError, "expected size >= %d, got %d", + sizeof(_PyBytes_data_t), size); + return NULL; + } + if (newfunc == NULL) { + if (size == sizeof(_PyBytes_data_t)) { + PyErr_SetString(PyExc_ValueError, "missing new_object func"); + return NULL; + } + newfunc = _PyBytes_FromXIData; + } + if (_bytes_shared(tstate, obj, size, newfunc, xidata) < 0) { + return NULL; + } + return (_PyBytes_data_t *)xidata->data; +} + // str struct _shared_str_data { @@ -608,7 +670,7 @@ _register_builtins_for_crossinterpreter_data(dlregistry_t *xidregistry) } // bytes - if (_xidregistry_add_type(xidregistry, &PyBytes_Type, _bytes_shared) != 0) { + if (_xidregistry_add_type(xidregistry, &PyBytes_Type, _PyBytes_GetXIData) != 0) { Py_FatalError("could not register bytes for cross-interpreter sharing"); } _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com