GH-128682: Change a couple of functions to only steal references on success. (GH-129132)

Change PyTuple_FromStackRefSteal and PyList_FromStackRefSteal to only steal on success to avoid escaping
This commit is contained in:
Mark Shannon 2025-01-22 10:51:37 +00:00 committed by GitHub
parent a65f802692
commit 470a0a68eb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 34 additions and 32 deletions

View file

@ -61,7 +61,7 @@ typedef struct {
union _PyStackRef; union _PyStackRef;
PyAPI_FUNC(PyObject *)_PyList_FromStackRefSteal(const union _PyStackRef *src, Py_ssize_t n); PyAPI_FUNC(PyObject *)_PyList_FromStackRefStealOnSuccess(const union _PyStackRef *src, Py_ssize_t n);
PyAPI_FUNC(PyObject *)_PyList_AsTupleAndClear(PyListObject *v); PyAPI_FUNC(PyObject *)_PyList_AsTupleAndClear(PyListObject *v);
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -2031,12 +2031,12 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = {
[BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
[BINARY_SUBSCR_STR_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [BINARY_SUBSCR_STR_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
[BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
[BUILD_LIST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, [BUILD_LIST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG },
[BUILD_MAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BUILD_MAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[BUILD_SET] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BUILD_SET] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[BUILD_SLICE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, [BUILD_SLICE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG },
[BUILD_STRING] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, [BUILD_STRING] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG },
[BUILD_TUPLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, [BUILD_TUPLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG },
[CACHE] = { true, INSTR_FMT_IX, 0 }, [CACHE] = { true, INSTR_FMT_IX, 0 },
[CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[CALL_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },

View file

@ -21,7 +21,7 @@ extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *);
#define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item) #define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item)
PyAPI_FUNC(PyObject *)_PyTuple_FromArray(PyObject *const *, Py_ssize_t); PyAPI_FUNC(PyObject *)_PyTuple_FromArray(PyObject *const *, Py_ssize_t);
PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefSteal(const union _PyStackRef *, Py_ssize_t); PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefStealOnSuccess(const union _PyStackRef *, Py_ssize_t);
PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t); PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t);
typedef struct { typedef struct {

View file

@ -137,8 +137,8 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_STORE_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ESCAPES_FLAG, [_STORE_DEREF] = HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ESCAPES_FLAG,
[_COPY_FREE_VARS] = HAS_ARG_FLAG, [_COPY_FREE_VARS] = HAS_ARG_FLAG,
[_BUILD_STRING] = HAS_ARG_FLAG | HAS_ERROR_FLAG, [_BUILD_STRING] = HAS_ARG_FLAG | HAS_ERROR_FLAG,
[_BUILD_TUPLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG, [_BUILD_TUPLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG,
[_BUILD_LIST] = HAS_ARG_FLAG | HAS_ERROR_FLAG, [_BUILD_LIST] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG,
[_LIST_EXTEND] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_LIST_EXTEND] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_SET_UPDATE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_SET_UPDATE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_BUILD_SET] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_BUILD_SET] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,

View file

@ -3190,7 +3190,7 @@ _PyList_AsTupleAndClear(PyListObject *self)
} }
PyObject * PyObject *
_PyList_FromStackRefSteal(const _PyStackRef *src, Py_ssize_t n) _PyList_FromStackRefStealOnSuccess(const _PyStackRef *src, Py_ssize_t n)
{ {
if (n == 0) { if (n == 0) {
return PyList_New(0); return PyList_New(0);
@ -3198,9 +3198,6 @@ _PyList_FromStackRefSteal(const _PyStackRef *src, Py_ssize_t n)
PyListObject *list = (PyListObject *)PyList_New(n); PyListObject *list = (PyListObject *)PyList_New(n);
if (list == NULL) { if (list == NULL) {
for (Py_ssize_t i = 0; i < n; i++) {
PyStackRef_CLOSE(src[i]);
}
return NULL; return NULL;
} }

View file

@ -391,16 +391,13 @@ _PyTuple_FromArray(PyObject *const *src, Py_ssize_t n)
} }
PyObject * PyObject *
_PyTuple_FromStackRefSteal(const _PyStackRef *src, Py_ssize_t n) _PyTuple_FromStackRefStealOnSuccess(const _PyStackRef *src, Py_ssize_t n)
{ {
if (n == 0) { if (n == 0) {
return tuple_get_empty(); return tuple_get_empty();
} }
PyTupleObject *tuple = tuple_alloc(n); PyTupleObject *tuple = tuple_alloc(n);
if (tuple == NULL) { if (tuple == NULL) {
for (Py_ssize_t i = 0; i < n; i++) {
PyStackRef_CLOSE(src[i]);
}
return NULL; return NULL;
} }
PyObject **dst = tuple->ob_item; PyObject **dst = tuple->ob_item;

View file

@ -1852,16 +1852,20 @@ dummy_func(
} }
inst(BUILD_TUPLE, (values[oparg] -- tup)) { inst(BUILD_TUPLE, (values[oparg] -- tup)) {
PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg); PyObject *tup_o = _PyTuple_FromStackRefStealOnSuccess(values, oparg);
if (tup_o == NULL) {
ERROR_NO_POP();
}
INPUTS_DEAD(); INPUTS_DEAD();
ERROR_IF(tup_o == NULL, error);
tup = PyStackRef_FromPyObjectSteal(tup_o); tup = PyStackRef_FromPyObjectSteal(tup_o);
} }
inst(BUILD_LIST, (values[oparg] -- list)) { inst(BUILD_LIST, (values[oparg] -- list)) {
PyObject *list_o = _PyList_FromStackRefSteal(values, oparg); PyObject *list_o = _PyList_FromStackRefStealOnSuccess(values, oparg);
if (list_o == NULL) {
ERROR_NO_POP();
}
INPUTS_DEAD(); INPUTS_DEAD();
ERROR_IF(list_o == NULL, error);
list = PyStackRef_FromPyObjectSteal(list_o); list = PyStackRef_FromPyObjectSteal(list_o);
} }

View file

@ -1527,7 +1527,12 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
u = (PyObject *)&_Py_SINGLETON(tuple_empty); u = (PyObject *)&_Py_SINGLETON(tuple_empty);
} }
else { else {
u = _PyTuple_FromStackRefSteal(args + n, argcount - n); u = _PyTuple_FromStackRefStealOnSuccess(args + n, argcount - n);
if (u == NULL) {
for (Py_ssize_t i = n; i < argcount; i++) {
PyStackRef_CLOSE(args[i]);
}
}
} }
if (u == NULL) { if (u == NULL) {
goto fail_post_positional; goto fail_post_positional;

View file

@ -2240,8 +2240,10 @@
_PyStackRef tup; _PyStackRef tup;
oparg = CURRENT_OPARG(); oparg = CURRENT_OPARG();
values = &stack_pointer[-oparg]; values = &stack_pointer[-oparg];
PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg); PyObject *tup_o = _PyTuple_FromStackRefStealOnSuccess(values, oparg);
if (tup_o == NULL) JUMP_TO_ERROR(); if (tup_o == NULL) {
JUMP_TO_ERROR();
}
tup = PyStackRef_FromPyObjectSteal(tup_o); tup = PyStackRef_FromPyObjectSteal(tup_o);
stack_pointer[-oparg] = tup; stack_pointer[-oparg] = tup;
stack_pointer += 1 - oparg; stack_pointer += 1 - oparg;
@ -2254,8 +2256,10 @@
_PyStackRef list; _PyStackRef list;
oparg = CURRENT_OPARG(); oparg = CURRENT_OPARG();
values = &stack_pointer[-oparg]; values = &stack_pointer[-oparg];
PyObject *list_o = _PyList_FromStackRefSteal(values, oparg); PyObject *list_o = _PyList_FromStackRefStealOnSuccess(values, oparg);
if (list_o == NULL) JUMP_TO_ERROR(); if (list_o == NULL) {
JUMP_TO_ERROR();
}
list = PyStackRef_FromPyObjectSteal(list_o); list = PyStackRef_FromPyObjectSteal(list_o);
stack_pointer[-oparg] = list; stack_pointer[-oparg] = list;
stack_pointer += 1 - oparg; stack_pointer += 1 - oparg;

View file

@ -732,10 +732,8 @@
_PyStackRef *values; _PyStackRef *values;
_PyStackRef list; _PyStackRef list;
values = &stack_pointer[-oparg]; values = &stack_pointer[-oparg];
PyObject *list_o = _PyList_FromStackRefSteal(values, oparg); PyObject *list_o = _PyList_FromStackRefStealOnSuccess(values, oparg);
if (list_o == NULL) { if (list_o == NULL) {
stack_pointer += -oparg;
assert(WITHIN_STACK_BOUNDS());
goto error; goto error;
} }
list = PyStackRef_FromPyObjectSteal(list_o); list = PyStackRef_FromPyObjectSteal(list_o);
@ -905,10 +903,8 @@
_PyStackRef *values; _PyStackRef *values;
_PyStackRef tup; _PyStackRef tup;
values = &stack_pointer[-oparg]; values = &stack_pointer[-oparg];
PyObject *tup_o = _PyTuple_FromStackRefSteal(values, oparg); PyObject *tup_o = _PyTuple_FromStackRefStealOnSuccess(values, oparg);
if (tup_o == NULL) { if (tup_o == NULL) {
stack_pointer += -oparg;
assert(WITHIN_STACK_BOUNDS());
goto error; goto error;
} }
tup = PyStackRef_FromPyObjectSteal(tup_o); tup = PyStackRef_FromPyObjectSteal(tup_o);

View file

@ -581,7 +581,7 @@ NON_ESCAPING_FUNCTIONS = (
"_PyGen_GetGeneratorFromFrame", "_PyGen_GetGeneratorFromFrame",
"_PyInterpreterState_GET", "_PyInterpreterState_GET",
"_PyList_AppendTakeRef", "_PyList_AppendTakeRef",
"_PyList_FromStackRefSteal", "_PyList_FromStackRefStealOnSuccess",
"_PyList_ITEMS", "_PyList_ITEMS",
"_PyLong_Add", "_PyLong_Add",
"_PyLong_CompactValue", "_PyLong_CompactValue",
@ -600,8 +600,7 @@ NON_ESCAPING_FUNCTIONS = (
"_PyObject_InlineValues", "_PyObject_InlineValues",
"_PyObject_ManagedDictPointer", "_PyObject_ManagedDictPointer",
"_PyThreadState_HasStackSpace", "_PyThreadState_HasStackSpace",
"_PyTuple_FromArraySteal", "_PyTuple_FromStackRefStealOnSuccess",
"_PyTuple_FromStackRefSteal",
"_PyTuple_ITEMS", "_PyTuple_ITEMS",
"_PyType_HasFeature", "_PyType_HasFeature",
"_PyType_NewManagedObject", "_PyType_NewManagedObject",