Skip to content

Commit ff9d044

Browse files
committed
Fix up after merge
1 parent 67670f0 commit ff9d044

File tree

5 files changed

+101
-24
lines changed

5 files changed

+101
-24
lines changed

Include/internal/pycore_frame.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *
157157
dest->stackpointer = dest->localsplus + stacktop;
158158
for (int i = 0; i < stacktop; i++) {
159159
dest->localsplus[i] = PyStackRef_HeapSafe(src->localsplus[i]);
160+
PyStackRef_CheckValid(dest->localsplus[i]);
160161
}
161162

162163
#ifdef Py_GIL_DISABLED
@@ -408,7 +409,7 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int
408409

409410
PyAPI_FUNC(_PyInterpreterFrame *)
410411
_PyEvalFramePushAndInit(PyThreadState *tstate, _PyStackRef func,
411-
PyObject *locals, _PyStackRef const* args,
412+
PyObject *locals, _PyStackRef const *args,
412413
size_t argcount, PyObject *kwnames,
413414
_PyInterpreterFrame *previous);
414415

Include/internal/pycore_stackref.h

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -200,22 +200,49 @@ PyStackRef_AsStrongReference(_PyStackRef stackref)
200200
// With GIL
201201

202202
#define Py_TAG_BITS 3
203+
#define Py_NULL_BIT 2
203204
#define Py_TAG_REFCNT 1
204-
#define Py_TAG_IMMORTAL 3
205205
#define BITS_TO_PTR(REF) ((PyObject *)((REF).bits))
206206
#define BITS_TO_PTR_MASKED(REF) ((PyObject *)(((REF).bits) & (~Py_TAG_BITS)))
207207

208-
#define PyStackRef_NULL_BITS Py_TAG_IMMORTAL
208+
#define PyStackRef_NULL_BITS (Py_TAG_REFCNT | Py_NULL_BIT)
209209
static const _PyStackRef PyStackRef_NULL = { .bits = PyStackRef_NULL_BITS };
210210

211211
#define PyStackRef_IsNull(ref) ((ref).bits == PyStackRef_NULL_BITS)
212-
#define PyStackRef_True ((_PyStackRef){.bits = ((uintptr_t)&_Py_TrueStruct) | Py_TAG_IMMORTAL })
213-
#define PyStackRef_False ((_PyStackRef){.bits = ((uintptr_t)&_Py_FalseStruct) | Py_TAG_IMMORTAL })
214-
#define PyStackRef_None ((_PyStackRef){.bits = ((uintptr_t)&_Py_NoneStruct) | Py_TAG_IMMORTAL })
212+
#define PyStackRef_True ((_PyStackRef){.bits = ((uintptr_t)&_Py_TrueStruct) | Py_TAG_REFCNT })
213+
#define PyStackRef_False ((_PyStackRef){.bits = ((uintptr_t)&_Py_FalseStruct) | Py_TAG_REFCNT })
214+
#define PyStackRef_None ((_PyStackRef){.bits = ((uintptr_t)&_Py_NoneStruct) | Py_TAG_REFCNT })
215215

216-
#define PyStackRef_IsTrue(ref) ((ref).bits == (((uintptr_t)&_Py_TrueStruct) | Py_TAG_IMMORTAL))
217-
#define PyStackRef_IsFalse(ref) ((ref).bits == (((uintptr_t)&_Py_NoneStruct) | Py_TAG_IMMORTAL))
218-
#define PyStackRef_IsNone(ref) ((ref).bits == (((uintptr_t)&_Py_NoneStruct) | Py_TAG_IMMORTAL))
216+
// #define PyStackRef_IsTrue(ref) ((ref).bits == (((uintptr_t)&_Py_TrueStruct) | Py_TAG_REFCNT))
217+
// #define PyStackRef_IsFalse(ref) ((ref).bits == (((uintptr_t)&_Py_FalseStruct) | Py_TAG_REFCNT))
218+
// #define PyStackRef_IsNone(ref) ((ref).bits == (((uintptr_t)&_Py_NoneStruct) | Py_TAG_REFCNT))
219+
220+
/* We should be able to guarantee that the tag bits are set for immortal objects */
221+
222+
#define PyStackRef_IsTrue(ref) (((ref).bits & (~Py_TAG_BITS)) == ((uintptr_t)&_Py_TrueStruct))
223+
#define PyStackRef_IsFalse(ref) (((ref).bits & (~Py_TAG_BITS)) == ((uintptr_t)&_Py_FalseStruct))
224+
// #define PyStackRef_IsNone(ref) (((ref).bits & (~Py_TAG_BITS)) == ((uintptr_t)&_Py_NoneStruct))
225+
226+
227+
static inline void PyStackRef_CheckValid(_PyStackRef ref) {
228+
int tag = ref.bits & Py_TAG_BITS;
229+
if (tag == PyStackRef_NULL_BITS) {
230+
assert(ref.bits == PyStackRef_NULL_BITS);
231+
}
232+
else if (tag == 0) {
233+
assert(!_Py_IsImmortal(BITS_TO_PTR_MASKED(ref)));
234+
}
235+
}
236+
237+
static inline int
238+
PyStackRef_IsNone(_PyStackRef ref)
239+
{
240+
if ((ref.bits & (~Py_TAG_BITS)) == ((uintptr_t)&_Py_NoneStruct)) {
241+
assert ((ref.bits & Py_TAG_BITS) == Py_TAG_REFCNT);
242+
return 1;
243+
}
244+
return 0;
245+
}
219246

220247
static inline int
221248
PyStackRef_HasCount(_PyStackRef ref)
@@ -224,7 +251,7 @@ PyStackRef_HasCount(_PyStackRef ref)
224251
}
225252

226253
static inline int
227-
PyStackRef_HasCountAndMortal(_PyStackRef ref)
254+
PyStackRef_HasCountAndNotNull(_PyStackRef ref)
228255
{
229256
return (ref.bits & Py_TAG_BITS) == Py_TAG_REFCNT;
230257
}
@@ -253,8 +280,9 @@ static inline _PyStackRef
253280
PyStackRef_FromPyObjectSteal(PyObject *obj)
254281
{
255282
assert(obj != NULL);
256-
unsigned int tag = _Py_IsImmortal(obj) ? Py_TAG_IMMORTAL : 0;
283+
unsigned int tag = _Py_IsImmortal(obj) ? Py_TAG_REFCNT : 0;
257284
_PyStackRef ref = ((_PyStackRef){.bits = ((uintptr_t)(obj)) | tag});
285+
PyStackRef_CheckValid(ref);
258286
return ref;
259287
}
260288

@@ -272,6 +300,7 @@ _PyStackRef_FromPyObjectNew(PyObject *obj)
272300
}
273301
Py_INCREF_MORTAL(obj);
274302
_PyStackRef ref = (_PyStackRef){ .bits = (uintptr_t)obj };
303+
PyStackRef_CheckValid(ref);
275304
return ref;
276305
}
277306
#define PyStackRef_FromPyObjectNew(obj) _PyStackRef_FromPyObjectNew(_PyObject_CAST(obj))
@@ -310,11 +339,16 @@ PyStackRef_IsHeapSafe(_PyStackRef ref)
310339
static inline _PyStackRef
311340
PyStackRef_HeapSafe(_PyStackRef ref)
312341
{
313-
if (PyStackRef_HasCountAndMortal(ref)) {
314-
PyObject *obj = BITS_TO_PTR_MASKED(ref);
315-
Py_INCREF_MORTAL(obj);
316-
ref.bits = (uintptr_t)obj;
342+
if (!PyStackRef_HasCountAndNotNull(ref)) {
343+
return ref;
344+
}
345+
PyObject *obj = BITS_TO_PTR_MASKED(ref);
346+
if (_Py_IsImmortal(obj)) {
347+
return ref;
317348
}
349+
Py_INCREF_MORTAL(obj);
350+
ref.bits = (uintptr_t)obj;
351+
PyStackRef_CheckValid(ref);
318352
return ref;
319353
}
320354

Python/ceval.c

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,6 +1515,7 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
15151515
}
15161516
assert(PyStackRef_IsNull(localsplus[i]));
15171517
localsplus[i] = PyStackRef_FromPyObjectSteal(kwdict);
1518+
PyStackRef_CheckValid(localsplus[i]);
15181519
}
15191520
else {
15201521
kwdict = NULL;
@@ -1531,6 +1532,7 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
15311532
for (j = 0; j < n; j++) {
15321533
assert(PyStackRef_IsNull(localsplus[j]));
15331534
localsplus[j] = args[j];
1535+
PyStackRef_CheckValid(localsplus[j]);
15341536
}
15351537

15361538
/* Pack other positional arguments into the *args argument */
@@ -1654,6 +1656,7 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
16541656
goto kw_fail;
16551657
}
16561658
localsplus[j] = value_stackref;
1659+
PyStackRef_CheckValid(localsplus[j]);
16571660
}
16581661
}
16591662

@@ -1689,6 +1692,7 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
16891692
if (PyStackRef_AsPyObjectBorrow(localsplus[m+i]) == NULL) {
16901693
PyObject *def = defs[i];
16911694
localsplus[m+i] = PyStackRef_FromPyObjectNew(def);
1695+
PyStackRef_CheckValid(localsplus[m+i]);
16921696
}
16931697
}
16941698
}
@@ -1708,6 +1712,7 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
17081712
}
17091713
if (def) {
17101714
localsplus[i] = PyStackRef_FromPyObjectSteal(def);
1715+
PyStackRef_CheckValid(localsplus[i]);
17111716
continue;
17121717
}
17131718
}
@@ -1835,12 +1840,27 @@ _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, _PyStackRef func,
18351840
PyStackRef_CLOSE(func);
18361841
goto error;
18371842
}
1843+
size_t total_args = nargs + PyDict_GET_SIZE(kwargs);
1844+
for (size_t i = 0; i < total_args; i++) {
1845+
((_PyStackRef *)newargs)[i] = PyStackRef_FromPyObjectSteal(newargs[i]);
1846+
}
18381847
}
18391848
else {
1840-
newargs = &PyTuple_GET_ITEM(callargs, 0);
1841-
/* We need to incref all our args since the new frame steals the references. */
1842-
for (Py_ssize_t i = 0; i < nargs; ++i) {
1843-
Py_INCREF(PyTuple_GET_ITEM(callargs, i));
1849+
if (nargs <= 8) {
1850+
PyObject *stack_array[8];
1851+
newargs = stack_array;
1852+
}
1853+
else {
1854+
newargs = PyMem_Malloc(sizeof(PyObject *) *nargs);
1855+
if (newargs == NULL) {
1856+
PyErr_NoMemory();
1857+
PyStackRef_CLOSE(func);
1858+
goto error;
1859+
}
1860+
}
1861+
/* We need to tag all our args since the new frame steals the references. */
1862+
for (Py_ssize_t i = 0; i < nargs; i++) {
1863+
((_PyStackRef *)newargs)[i] = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(callargs, i));
18441864
}
18451865
}
18461866
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
@@ -1850,6 +1870,9 @@ _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, _PyStackRef func,
18501870
if (has_dict) {
18511871
_PyStack_UnpackDict_FreeNoDecRef(newargs, kwnames);
18521872
}
1873+
else if (nargs > 8) {
1874+
PyMem_Free((void *)newargs);
1875+
}
18531876
/* No need to decref func here because the reference has been stolen by
18541877
_PyEvalFramePushAndInit.
18551878
*/
@@ -1868,21 +1891,39 @@ _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func,
18681891
PyObject* const* args, size_t argcount,
18691892
PyObject *kwnames)
18701893
{
1894+
size_t total_args = argcount;
1895+
if (kwnames) {
1896+
total_args += PyTuple_GET_SIZE(kwnames);
1897+
}
1898+
_PyStackRef *arguments;
1899+
if (total_args <= 8) {
1900+
_PyStackRef stack_array[8];
1901+
arguments = stack_array;
1902+
}
1903+
else {
1904+
arguments = PyMem_Malloc(sizeof(_PyStackRef) * total_args);
1905+
if (arguments == NULL) {
1906+
return PyErr_NoMemory();
1907+
}
1908+
}
18711909
/* _PyEvalFramePushAndInit consumes the references
18721910
* to func, locals and all its arguments */
18731911
Py_XINCREF(locals);
18741912
for (size_t i = 0; i < argcount; i++) {
1875-
Py_INCREF(args[i]);
1913+
arguments[i] = _PyStackRef_FromPyObjectNew(args[i]);
18761914
}
18771915
if (kwnames) {
18781916
Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames);
18791917
for (Py_ssize_t i = 0; i < kwcount; i++) {
1880-
Py_INCREF(args[i+argcount]);
1918+
arguments[i+argcount] = _PyStackRef_FromPyObjectNew(args[i+argcount]);
18811919
}
18821920
}
18831921
_PyInterpreterFrame *frame = _PyEvalFramePushAndInit(
18841922
tstate, PyStackRef_FromPyObjectNew(func), locals,
1885-
(_PyStackRef const *)args, argcount, kwnames, NULL);
1923+
arguments, argcount, kwnames, NULL);
1924+
if (total_args > 8) {
1925+
PyMem_Free(arguments);
1926+
}
18861927
if (frame == NULL) {
18871928
return NULL;
18881929
}

Python/ceval_macros.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ GETITEM(PyObject *v, Py_ssize_t i) {
257257
variable would be pointing to already-freed memory. */
258258
#define SETLOCAL(i, value) do { _PyStackRef tmp = GETLOCAL(i); \
259259
GETLOCAL(i) = value; \
260+
PyStackRef_CheckValid(value); \
260261
PyStackRef_XCLOSE(tmp); } while (0)
261262

262263
#define GO_TO_INSTRUCTION(op) goto PREDICT_ID(op)

Python/frame.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
6060
// This may be a newly-created generator or coroutine frame. Since it's
6161
// dead anyways, just pretend that the first RESUME ran:
6262
PyCodeObject *code = _PyFrame_GetCode(new_frame);
63-
frame->instr_ptr =
64-
_PyFrame_GetBytecode(frame) + code->_co_firsttraceable + 1;
63+
new_frame->instr_ptr =
64+
_PyFrame_GetBytecode(new_frame) + code->_co_firsttraceable + 1;
6565
}
6666
assert(!_PyFrame_IsIncomplete(new_frame));
6767
assert(f->f_back == NULL);

0 commit comments

Comments
 (0)