GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing github.com — [C API] Py_CLEAR(), Py_SETREF() and Py_XSETREF() memcpy() implementation is not safe with strict aliasing · Issue #161185 · python/cpython Closed Labels interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-C-APItype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error DescriptionIssue reported by @ngoldbaum on pythoncapi-compat: python/pythoncapi-compat#187 (comment). Copy/paste of his message. I asked an AI model to look this over and it spotted an issue (CPython's fallback also has this problem): The PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); PyObject *_tmp_old_dst = (*_tmp_dst_ptr); If Here is a standalone reproducer using the exact #include <Python.h> #include <cstdio> #include <cstring> #ifndef _Py_CAST # define _Py_CAST(type, expr) ((type)(expr)) #endif #ifndef _PyObject_CAST # define _PyObject_CAST(obj) _Py_CAST(PyObject *, (obj)) #endif #define REPRO_XSETREF(dst, src) \ do { \ PyObject **_tmp_dst_ptr = _Py_CAST(PyObject **, &(dst)); \ PyObject *_tmp_old_dst = (*_tmp_dst_ptr); \ PyObject *_tmp_src = _PyObject_CAST(src); \ memcpy(_tmp_dst_ptr, &_tmp_src, sizeof(PyObject *)); \ Py_XDECREF(_tmp_old_dst); \ } while (0) __attribute__((noinline)) static void replace(PyTypeObject **a, PyTypeObject **b, PyTypeObject *first, PyTypeObject *second) { *a = first; REPRO_XSETREF(*b, second); } int main() { Py_Initialize(); PyType_Slot slots[] = {{0, NULL}}; PyType_Spec spec = { "repro.T", sizeof(PyObject), 0, Py_TPFLAGS_DEFAULT, slots }; PyObject *first = PyType_FromSpec(&spec); PyObject *second = PyType_FromSpec(&spec); if (first == NULL || second == NULL) { PyErr_Print(); return 1; } Py_ssize_t before = Py_REFCNT(first); PyTypeObject *slot = NULL; // Both pointer arguments alias. The assignment makes first the old value // that REPRO_XSETREF() must release before storing second. replace(&slot, &slot, reinterpret_cast<PyTypeObject *>(Py_NewRef(first)), reinterpret_cast<PyTypeObject *>(Py_NewRef(second))); std::printf("first refcount: %zd; expected: %zd\n", Py_REFCNT(first), before); return 0; } On CPython 3.10 with GCC 15.2.0: $ g++ -std=c++11 $(python3.10-config --cflags) \ -DPy_LIMITED_API=0x030a0000 -O2 -fstrict-aliasing \ repro.cpp $(python3.10-config --embed --ldflags) -o repro $ ./repro first refcount: 3; expected: 2 The reference acquired by With Linked PRs
Activity
MetadataMetadataAssigneesLabelsinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)topic-C-APItype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error ProjectsMilestoneRelationshipsDevelopmentIssue actions |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |