FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-98724: Fix the Py_CLEAR() macro in the limited C API by vstinner · Pull Request #100121 · python/cpython · GitHub

/ cpython Public
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .c  (3) .h  (1) .py  (1) .toml  (1) All 4 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
8 changes: 8 additions & 0 deletions Include/object.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,13 @@ static inline void Py_DECREF(PyObject *op)
* and so avoid type punning. Otherwise, use memcpy() which causes type erasure
* and so prevents the compiler to reuse an old cached 'op' value after
* Py_CLEAR().
*
* If _Py_TYPEOF() is not available, the limited C API implementation uses a
* function call to hide implementation details. The function uses memcpy() of
* <string.h> which is not included by <Python.h>.
*/
PyAPI_FUNC(void) _Py_Clear(PyObject **pobj);

#ifdef _Py_TYPEOF
#define Py_CLEAR(op) \
do { \
Expand All @@ -623,6 +629,8 @@ static inline void Py_DECREF(PyObject *op)
Py_DECREF(_tmp_old_op); \
} \
} while (0)
#elif defined(Py_LIMITED_API)
#define Py_CLEAR(op) _Py_Clear(_Py_CAST(PyObject**, &(op)))
#else
#define Py_CLEAR(op) \
do { \
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_stable_abi_ctypes.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Misc/stable_abi.toml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -2386,3 +2386,7 @@
added = '3.12' # Before 3.12, available in "structmember.h" w/o Py_ prefix
[const.Py_AUDIT_READ]
added = '3.12' # Before 3.12, available in "structmember.h"

[function._Py_Clear]
added = '3.12'
abi_only = true
34 changes: 30 additions & 4 deletions Modules/_testcapimodule.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -2593,27 +2593,53 @@ test_set_type_size(PyObject *self, PyObject *Py_UNUSED(ignored))
static PyObject*
test_py_clear(PyObject *self, PyObject *Py_UNUSED(ignored))
{
PyObject *list = PyList_New(0);
if (list == NULL) {
return NULL;
}
assert(Py_REFCNT(list) == 1);

// simple case with a variable
PyObject *obj = PyList_New(0);
PyObject *obj = Py_NewRef(list);
if (obj == NULL) {
return NULL;
goto error;
}
assert(Py_REFCNT(list) == 2);
Py_CLEAR(obj);
assert(Py_REFCNT(list) == 1);
assert(obj == NULL);

// test _Py_Clear() used by the limited C API
PyObject *obj2 = Py_NewRef(list);
if (obj2 == NULL) {
goto error;
}
assert(Py_REFCNT(list) == 2);
_Py_Clear(&obj2);
assert(Py_REFCNT(list) == 1);
assert(obj2 == NULL);

// gh-98724: complex case, Py_CLEAR() argument has a side effect
PyObject* array[1];
array[0] = PyList_New(0);
array[0] = Py_NewRef(list);
if (array[0] == NULL) {
return NULL;
goto error;
}

PyObject **p = array;
assert(Py_REFCNT(list) == 2);
Py_CLEAR(*p++);
assert(Py_REFCNT(list) == 1);
assert(array[0] == NULL);
assert(p == array + 1);

assert(Py_REFCNT(list) == 1);
Py_DECREF(list);
Py_RETURN_NONE;

error:
Py_DECREF(list);
return NULL;
}


Expand Down
17 changes: 17 additions & 0 deletions Objects/object.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -2446,6 +2446,23 @@ int Py_IsFalse(PyObject *x)
return Py_Is(x, Py_False);
}

void _Py_Clear(PyObject **pobj)
{
PyObject *old_obj = *pobj;
if (old_obj == NULL) {
return;
}

// gh-99701: In the limited C API, the Py_CLEAR(obj) macro has a type
// punning issue, it casts '&obj' to PyObject** to call _Py_Clear(). Use
// memcpy() instead of a simple assignment to cause type erasure and so
// prevent the compiler to reuse an old cached 'obj' value after
// Py_CLEAR().
PyObject *null_ptr = NULL;
memcpy(pobj, &null_ptr, sizeof(PyObject*));
Py_DECREF(old_obj);
}

#ifdef __cplusplus
}
#endif
1 change: 1 addition & 0 deletions PC/python3dll.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.


Back | FazBrowse Home | New Git URL