8000 gh-135552: Skip clearing of tp_subclasses weakrefs in GC by sergey-miryanov · Pull Request #136147 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-135552: Skip clearing of tp_subclasses weakrefs in GC #136147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f14f0ba
Reset type cache after finalization
sergey-miryanov Jun 19, 2025
61fc657
Add tests
fxeqxmulfx Jun 22, 2025
d8124a9
Organize tests
sergey-miryanov Jun 22, 2025
bb21510
Remove wrong solution
sergey-miryanov Jun 22, 2025
0e649ab
Do not clear weakrefs to types before finalization of instances
sergey-miryanov Jun 22, 2025
ff79617
Merge branch 'main' into gh-135552-fix-gc-segfault
sergey-miryanov Jun 22, 2025
ac394bc
Add news
sergey-miryanov Jun 22, 2025
3b18738
Update Misc/NEWS.d/next/Core_and_Builtins/2025-06-23-01-07-09.gh-issu…
sergey-miryanov Jun 23, 2025
de8841c
Update Misc/NEWS.d/next/Core_and_Builtins/2025-06-23-01-07-09.gh-issu…
sergey-miryanov Jun 23, 2025
f8745e0
Split unreachable to types and objects while deduce
sergey-miryanov Jun 23, 2025
f166933
Merge branch 'gh-135552-fix-gc-segfault' of github.com:sergey-miryano…
sergey-miryanov Jun 23, 2025
3fe0f15
Simplify tests
sergey-miryanov Jun 24, 2025
96f09db
Merge branch 'main' into gh-135552-fix-gc-segfault-2
sergey-miryanov Jun 30, 2025
1ad18ec
Remove unreachable_types pass
sergey-miryanov Jun 30, 2025
bc0297c
Remove obsolete comments
sergey-miryanov Jun 30, 2025
3294f2e
Add is_subclass to PyWeakReference and do not clear those weakrefs in GC
sergey-miryanov Jun 30, 2025
6c45159
Create weakrefs for subclasses with sentinel callback to properly han…
sergey-miryanov Jul 1, 2025
e5e95ff
Update news entry
sergey-miryanov Jul 1, 2025
edf634c
Add some comments
sergey-miryanov Jul 1, 2025
bd7d9f3
Crazy idea to use noop-callback as a sentinel
sergey-miryanov Jul 2, 2025
987f6a3
Immortalize sentinel callback
sergey-miryanov Jul 2, 2025
be87675
Clear weakref sentinel in the right place
sergey-miryanov Jul 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Crazy idea to use noop-callback as a sentinel
  • Loading branch information
sergey-miryanov committed Jul 2, 2025
commit bd7d9f3f82965da0d36ad65e80bec42f6cf6422c
134 changes: 123 additions & 11 deletions Objects/weakrefobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
#include "pycore_lock.h"
#include "pycore_modsupport.h" // _PyArg_NoKwnames()
#include "pycore_object.h" // _PyObject_GET_WEAKREFS_LISTPTR()
#include "pycore_opcode_metadata.h" // RESUME
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_pystate.h"
#include "pycore_weakref.h" // _PyWeakref_GET_REF()



#ifdef Py_GIL_DISABLED
/*
* Thread-safety for free-threaded builds
Expand Down Expand Up @@ -1135,32 +1138,141 @@ _PyWeakref_IsDead(PyObject *weakref)
return _PyWeakref_IS_DEAD(weakref);
}

static const uint8_t noop_func_bytecode[6] = {
RESUME, RESUME_AT_FUNC_START,
LOAD_CONST, 0,
RETURN_VALUE, 0
};

static const uint8_t noop_func_linetable[2] = {
(1 << 7) // New entry.
| (PY_CODE_LOCATION_INFO_NO_COLUMNS << 3)
| (3 - 1), // Three code units.
0, // Offset from co_firstlineno.
};

PyCodeObject *
create_new_noop_code(const char *filename, const char *funcname, int firstlineno)
{
PyObject *nulltuple = NULL;
PyObject *filename_str = NULL;
PyObject *funcname_str = NULL;
PyObject *code_bytes = NULL;
PyObject *linetable_bytes = NULL;
PyObject *wr_str = NULL;
PyObject *consts = NULL;
PyObject *varnames = NULL;
PyCodeObject *result = NULL;

nulltuple = PyTuple_New(0);
if (nulltuple == NULL) {
goto failed;
}
funcname_str = PyUnicode_FromString(funcname);
if (funcname_str == NULL) {
goto failed;
}
filename_str = PyUnicode_FromString(filename);
if (filename_str == NULL) {
goto failed;
}
code_bytes = PyBytes_FromStringAndSize((const char *)noop_func_bytecode, 6);
if (code_bytes == NULL) {
goto failed;
}
linetable_bytes = PyBytes_FromStringAndSize((const char *)noop_func_linetable, 2);
if (linetable_bytes == NULL) {
goto failed;
}

consts = PyTuple_Pack(1, Py_None);
if (consts == NULL) {
goto failed;
}

wr_str = PyUnicode_FromString("wr");
if (wr_str == NULL) {
goto failed;
}

varnames = PyTuple_Pack(1, wr_str);
if (varnames == NULL) {
goto failed;
}
#define emptybytes (PyObject *)&_Py_SINGLETON(bytes_empty)

int argcount = 1;
int posonlyargcount = 0;
int kwonlyargcount = 0;
int nlocals = 1;
int stacksize = 1;
int flags = CO_OPTIMIZED | CO_NEWLOCALS;

result = PyUnstable_Code_NewWithPosOnlyArgs(
argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize, flags,
code_bytes, consts, nulltuple, varnames, nulltuple, nulltuple,
filename_str, funcname_str, funcname_str, firstlineno,
linetable_bytes, emptybytes);

#undef emptybytes

failed:
Py_XDECREF(nulltuple);
Py_XDECREF(funcname_str);
Py_XDECREF(filename_str);
Py_XDECREF(code_bytes);
Py_XDECREF(linetable_bytes);
Py_XDECREF(consts);
Py_XDECREF(varnames);
Py_XDECREF(wr_str);

return result;
}

int
_PyWeakref_InitSubclassSentinel(PyInterpreterState *interp)
{
PyObject *code = (PyObject *)PyCode_NewEmpty(
int status = 0;

PyObject *globals = NULL;
PyObject *func = NULL;
PyObject *code = (PyObject *)create_new_noop_code(
"<generated>",
"<subclasses_weakref_sentinel>",
0);
1);
if (code == NULL) {
return -1;
}

PyObject *globals = PyDict_New();
globals = PyDict_New();
if (globals == NULL) {
Py_DECREF(code);
return -1;
status = -1;
goto failed;
}

PyObject *func = PyFunction_New(code, globals);
Py_DECREF(globals);
Py_DECREF(code);
func = PyFunction_New(code, globals);
if (func == NULL) {
return -1;
status = -1;
goto failed;
}

#ifdef Py_DEBUG
PyObject *result = PyObject_CallOneArg(func, Py_None);
if (!result) {
status = -1;
goto failed;
}
Py_DECREF(result);
#endif

_Py_INTERP_SINGLETON(interp, subclasses_weakref_sentinel) = func;
return 0;

failed:
Py_XDECREF(code);
Py_XDECREF(globals);

return status;
}

PyObject *
Expand All @@ -1184,5 +1296,5 @@ _PyWeakref_IsSubclassRef(PyWeakReference *weakref)
interp = interp->runtime->interpreters.main;
}
PyObject *func = _Py_INTERP_SINGLETON(interp, subclasses_weakref_sentinel);
return weakref->wr_callback == func;
return func != NULL && weakref->wr_callback == func;
}
Loading
0