summaryrefslogtreecommitdiffstats
path: root/Python/stackrefs.c
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2025-03-05 14:00:42 (GMT)
committerGitHub <noreply@github.com>2025-03-05 14:00:42 (GMT)
commit78d50e91ff31bc7fd0ac877cf59ee083e94d0915 (patch)
tree2cc8ea2a2767bc283816829e3f0ea28c4046367b /Python/stackrefs.c
parentf33d21e24fdb05da7512c2a203467c3ffd0e7713 (diff)
downloadcpython-78d50e91ff31bc7fd0ac877cf59ee083e94d0915.zip
cpython-78d50e91ff31bc7fd0ac877cf59ee083e94d0915.tar.gz
cpython-78d50e91ff31bc7fd0ac877cf59ee083e94d0915.tar.bz2
GH-127705: better double free message. (GH-130785)
* Add location information when accessing already closed stackref * Add #def option to track closed stackrefs to provide precise information for use after free and double frees.
Diffstat (limited to 'Python/stackrefs.c')
-rw-r--r--Python/stackrefs.c46
1 files changed, 36 insertions, 10 deletions
diff --git a/Python/stackrefs.c b/Python/stackrefs.c
index 9bb4689..2e889b1 100644
--- a/Python/stackrefs.c
+++ b/Python/stackrefs.c
@@ -47,7 +47,7 @@ _Py_stackref_get_object(_PyStackRef ref)
if (ref.index >= interp->next_stackref) {
_Py_FatalErrorFormat(__func__, "Garbled stack ref with ID %" PRIu64 "\n", ref.index);
}
- TableEntry *entry = _Py_hashtable_get(interp->stackref_debug_table, (void *)ref.index);
+ TableEntry *entry = _Py_hashtable_get(interp->open_stackrefs_table, (void *)ref.index);
if (entry == NULL) {
_Py_FatalErrorFormat(__func__, "Accessing closed stack ref with ID %" PRIu64 "\n", ref.index);
}
@@ -55,25 +55,43 @@ _Py_stackref_get_object(_PyStackRef ref)
}
PyObject *
-_Py_stackref_close(_PyStackRef ref)
+_Py_stackref_close(_PyStackRef ref, const char *filename, int linenumber)
{
PyInterpreterState *interp = PyInterpreterState_Get();
if (ref.index >= interp->next_stackref) {
- _Py_FatalErrorFormat(__func__, "Garbled stack ref with ID %" PRIu64 "\n", ref.index);
+ _Py_FatalErrorFormat(__func__, "Invalid StackRef with ID %" PRIu64 " at %s:%d\n", (void *)ref.index, filename, linenumber);
+
}
PyObject *obj;
if (ref.index <= LAST_PREDEFINED_STACKREF_INDEX) {
// Pre-allocated reference to None, False or True -- Do not clear
- TableEntry *entry = _Py_hashtable_get(interp->stackref_debug_table, (void *)ref.index);
+ TableEntry *entry = _Py_hashtable_get(interp->open_stackrefs_table, (void *)ref.index);
obj = entry->obj;
}
else {
- TableEntry *entry = _Py_hashtable_steal(interp->stackref_debug_table, (void *)ref.index);
+ TableEntry *entry = _Py_hashtable_steal(interp->open_stackrefs_table, (void *)ref.index);
if (entry == NULL) {
+#ifdef Py_STACKREF_CLOSE_DEBUG
+ entry = _Py_hashtable_get(interp->closed_stackrefs_table, (void *)ref.index);
+ if (entry != NULL) {
+ _Py_FatalErrorFormat(__func__,
+ "Double close of ref ID %" PRIu64 " at %s:%d. Referred to instance of %s at %p. Closed at %s:%d\n",
+ (void *)ref.index, filename, linenumber, entry->classname, entry->obj, entry->filename, entry->linenumber);
+ }
+#endif
_Py_FatalErrorFormat(__func__, "Invalid StackRef with ID %" PRIu64 "\n", (void *)ref.index);
}
obj = entry->obj;
free(entry);
+#ifdef Py_STACKREF_CLOSE_DEBUG
+ TableEntry *close_entry = make_table_entry(obj, filename, linenumber);
+ if (close_entry == NULL) {
+ Py_FatalError("No memory left for stackref debug table");
+ }
+ if (_Py_hashtable_set(interp->closed_stackrefs_table, (void *)ref.index, close_entry) < 0) {
+ Py_FatalError("No memory left for stackref debug table");
+ }
+#endif
}
return obj;
}
@@ -90,7 +108,7 @@ _Py_stackref_create(PyObject *obj, const char *filename, int linenumber)
if (entry == NULL) {
Py_FatalError("No memory left for stackref debug table");
}
- if (_Py_hashtable_set(interp->stackref_debug_table, (void *)new_id, entry) < 0) {
+ if (_Py_hashtable_set(interp->open_stackrefs_table, (void *)new_id, entry) < 0) {
Py_FatalError("No memory left for stackref debug table");
}
return (_PyStackRef){ .index = new_id };
@@ -103,9 +121,17 @@ _Py_stackref_record_borrow(_PyStackRef ref, const char *filename, int linenumber
return;
}
PyInterpreterState *interp = PyInterpreterState_Get();
- TableEntry *entry = _Py_hashtable_get(interp->stackref_debug_table, (void *)ref.index);
+ TableEntry *entry = _Py_hashtable_get(interp->open_stackrefs_table, (void *)ref.index);
if (entry == NULL) {
- _Py_FatalErrorFormat(__func__, "Invalid StackRef with ID %" PRIu64 "\n", (void *)ref.index);
+#ifdef Py_STACKREF_CLOSE_DEBUG
+ entry = _Py_hashtable_get(interp->closed_stackrefs_table, (void *)ref.index);
+ if (entry != NULL) {
+ _Py_FatalErrorFormat(__func__,
+ "Borrow of closed ref ID %" PRIu64 " at %s:%d. Referred to instance of %s at %p. Closed at %s:%d\n",
+ (void *)ref.index, filename, linenumber, entry->classname, entry->obj, entry->filename, entry->linenumber);
+ }
+#endif
+ _Py_FatalErrorFormat(__func__, "Invalid StackRef with ID %" PRIu64 " at %s:%d\n", (void *)ref.index, filename, linenumber);
}
entry->filename_borrow = filename;
entry->linenumber_borrow = linenumber;
@@ -121,7 +147,7 @@ _Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _PyStackRef re
if (entry == NULL) {
Py_FatalError("No memory left for stackref debug table");
}
- if (_Py_hashtable_set(interp->stackref_debug_table, (void *)ref.index, (void *)entry) < 0) {
+ if (_Py_hashtable_set(interp->open_stackrefs_table, (void *)ref.index, (void *)entry) < 0) {
Py_FatalError("No memory left for stackref debug table");
}
}
@@ -147,7 +173,7 @@ void
_Py_stackref_report_leaks(PyInterpreterState *interp)
{
int leak = 0;
- _Py_hashtable_foreach(interp->stackref_debug_table, report_leak, &leak);
+ _Py_hashtable_foreach(interp->open_stackrefs_table, report_leak, &leak);
if (leak) {
Py_FatalError("Stackrefs leaked.");
}