From cb85ea4eb0f5b691269c076adc177b7d7e95992b Mon Sep 17 00:00:00 2001 From: sunmy2019 <59365878+sunmy2019@users.noreply.github.com> Date: Wed, 19 Apr 2023 23:35:16 +0800 Subject: [PATCH 1/3] demo of memory tracking with cpp shared lib --- Include/cpython/object.h | 4 ++ Include/internal/pycore_object.h | 5 +- Include/object.h | 10 +++ Modules/gcmodule.c | 10 ++- Objects/bytesobject.c | 8 ++- Objects/dictobject.c | 5 ++ Objects/moduleobject.c | 2 +- Objects/object.c | 4 ++ Objects/structseq.c | 3 +- Objects/tupleobject.c | 1 + Objects/typeobject.c | 1 - Objects/unicodeobject.c | 11 ++- Python/sysmodule.c | 7 ++ cb.cpp | 115 +++++++++++++++++++++++++++++++ 14 files changed, 177 insertions(+), 9 deletions(-) create mode 100644 cb.cpp diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 98cc51cd7fee49..b46b1ec10ecf57 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -230,6 +230,10 @@ struct _typeobject { char tp_watched; }; +const char* __attribute__((weak)) get_type_name(PyTypeObject* type) { + return type ? type->tp_name : "NULL"; +} + /* This struct is used by the specializer * It should should be treated as an opaque blob * by code other than the specializer and interpreter. */ diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index b3d496ed6fc240..857d6a6acc6467 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -56,6 +56,7 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n) { #ifdef Py_REF_DEBUG _Py_AddRefTotal(_PyInterpreterState_GET(), n); + state_change(op, op->ob_refcnt + n, +n, get_type_name(op->ob_type), _Py_GetGlobalRefTotal()); #endif op->ob_refcnt += n; } @@ -65,8 +66,9 @@ static inline void _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct) { _Py_DECREF_STAT_INC(); -#ifdef Py_REF_DEBUG +#ifdef Py_REF_DEBUG _Py_DEC_REFTOTAL(_PyInterpreterState_GET()); + state_change(op, op->ob_refcnt - 1, -1, get_type_name(op->ob_type), _Py_GetGlobalRefTotal()); #endif if (--op->ob_refcnt != 0) { assert(op->ob_refcnt > 0); @@ -85,6 +87,7 @@ _Py_DECREF_NO_DEALLOC(PyObject *op) _Py_DECREF_STAT_INC(); #ifdef Py_REF_DEBUG _Py_DEC_REFTOTAL(_PyInterpreterState_GET()); + state_change(op, op->ob_refcnt - 1, -1, get_type_name(op->ob_type), _Py_GetGlobalRefTotal()); #endif op->ob_refcnt--; #ifdef Py_DEBUG diff --git a/Include/object.h b/Include/object.h index 2943a6066818cd..cfcff6361c4f1e 100644 --- a/Include/object.h +++ b/Include/object.h @@ -1,9 +1,16 @@ #ifndef Py_OBJECT_H #define Py_OBJECT_H +#include "pytypedefs.h" #ifdef __cplusplus extern "C" { #endif +extern long _Py_GetGlobalRefTotal(void); +extern void state_change(void *ptr, long rc, long diff, const char *type, + long current_total_ref); +extern void store_state(); +extern void check_with_stored_state(); +extern const char* get_type_name(PyTypeObject* type); /* Object and type object interface */ @@ -162,6 +169,7 @@ static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) { static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) { + state_change(ob, refcnt, 0, get_type_name(ob->ob_type), _Py_GetGlobalRefTotal()); ob->ob_refcnt = refcnt; } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 @@ -535,6 +543,7 @@ static inline void Py_INCREF(PyObject *op) // directly PyObject.ob_refcnt. #ifdef Py_REF_DEBUG _Py_INC_REFTOTAL(); + state_change(op, op->ob_refcnt + 1, +1, get_type_name(op->ob_type), _Py_GetGlobalRefTotal()); #endif // Py_REF_DEBUG op->ob_refcnt++; #endif @@ -555,6 +564,7 @@ static inline void Py_DECREF(const char *filename, int lineno, PyObject *op) { _Py_DECREF_STAT_INC(); _Py_DEC_REFTOTAL(); + state_change(op, op->ob_refcnt - 1, -1, get_type_name(op->ob_type), _Py_GetGlobalRefTotal()); if (--op->ob_refcnt != 0) { if (op->ob_refcnt < 0) { _Py_NegativeRefcount(filename, lineno, op); diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 4eaa5490b6134c..7b1d7c0605a445 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -24,6 +24,7 @@ */ #include "Python.h" +#include "object.h" #include "pycore_context.h" #include "pycore_initconfig.h" #include "pycore_interp.h" // PyInterpreterState.gc @@ -2353,11 +2354,16 @@ _PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems) return (PyVarObject *)PyErr_NoMemory(); } + long old_refcnt = op->ob_base.ob_refcnt; + state_change(op, 0, 0, op->ob_base.ob_type->tp_name, + _Py_GetGlobalRefTotal()); PyGC_Head *g = AS_GC(op); - g = (PyGC_Head *)PyObject_Realloc(g, sizeof(PyGC_Head) + basicsize); + g = (PyGC_Head *)PyObject_Realloc(g, sizeof(PyGC_Head) + basicsize); if (g == NULL) return (PyVarObject *)PyErr_NoMemory(); - op = (PyVarObject *) FROM_GC(g); + op = (PyVarObject *)FROM_GC(g); + state_change(op, old_refcnt, 0, op->ob_base.ob_type->tp_name, + _Py_GetGlobalRefTotal()); Py_SET_SIZE(op, nitems); return op; } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 2d8dab6f378006..9c6bcb71dcca54 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -3063,16 +3063,22 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize) #ifdef Py_TRACE_REFS _Py_ForgetReference(v); #endif + + long old_refcnt = v->ob_refcnt; + state_change(v, 0, 0, "PyDictKeysObject", _Py_GetGlobalRefTotal()); + *pv = (PyObject *) PyObject_Realloc(v, PyBytesObject_SIZE + newsize); if (*pv == NULL) { #ifdef Py_REF_DEBUG - _Py_DecRefTotal(_PyInterpreterState_GET()); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif PyObject_Free(v); PyErr_NoMemory(); return -1; } + state_change(pv, old_refcnt, 0, "PyDictKeysObject", _Py_GetGlobalRefTotal()); + _Py_NewReferenceNoTotal(*pv); sv = (PyBytesObject *) *pv; Py_SET_SIZE(sv, newsize); diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 2ef520044340ee..fd29965c0403ff 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -305,6 +305,7 @@ dictkeys_incref(PyDictKeysObject *dk) { #ifdef Py_REF_DEBUG _Py_IncRefTotal(_PyInterpreterState_GET()); + state_change(dk, -1, +1, "PyDictKeysObject", _Py_GetGlobalRefTotal()); #endif dk->dk_refcnt++; } @@ -315,6 +316,7 @@ dictkeys_decref(PyInterpreterState *interp, PyDictKeysObject *dk) assert(dk->dk_refcnt > 0); #ifdef Py_REF_DEBUG _Py_DecRefTotal(_PyInterpreterState_GET()); + state_change(dk, -1, -1, "PyDictKeysObject", _Py_GetGlobalRefTotal()); #endif if (--dk->dk_refcnt == 0) { free_keys_object(interp, dk); @@ -635,6 +637,7 @@ new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode) } #ifdef Py_REF_DEBUG _Py_IncRefTotal(_PyInterpreterState_GET()); + state_change(dk, -1, +1, "PyDictKeysObject", _Py_GetGlobalRefTotal()); #endif dk->dk_refcnt = 1; dk->dk_log2_size = log2_size; @@ -825,6 +828,7 @@ clone_combined_dict_keys(PyDictObject *orig) keys->dk_refcnt is already set to 1 (after memcpy). */ #ifdef Py_REF_DEBUG _Py_IncRefTotal(_PyInterpreterState_GET()); + state_change(keys, -1, +1, "PyDictKeysObject", _Py_GetGlobalRefTotal()); #endif return keys; } @@ -1531,6 +1535,7 @@ dictresize(PyInterpreterState *interp, PyDictObject *mp, // are moved already. #ifdef Py_REF_DEBUG _Py_DecRefTotal(_PyInterpreterState_GET()); + state_change(oldkeys, -1, -1, "PyDictKeysObject", _Py_GetGlobalRefTotal()); #endif if (oldkeys == Py_EMPTY_KEYS) { oldkeys->dk_refcnt--; diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index a0be19a3ca8ac8..afbf03eaff1300 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -42,8 +42,8 @@ PyModuleDef_Init(PyModuleDef* def) { assert(PyModuleDef_Type.tp_flags & Py_TPFLAGS_READY); if (def->m_base.m_index == 0) { - Py_SET_REFCNT(def, 1); Py_SET_TYPE(def, &PyModuleDef_Type); + Py_SET_REFCNT(def, 1); def->m_base.m_index = _PyImport_GetNextModuleIndex(); } return (PyObject*)def; diff --git a/Objects/object.c b/Objects/object.c index 56747fa193e178..963b4f3f0087bf 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -72,6 +72,9 @@ get_legacy_reftotal(void) static inline void reftotal_increment(PyInterpreterState *interp) { + // if ( REFTOTAL(interp) >= 26600){ + // fprintf(stderr, "here -----> %p\n", &( REFTOTAL(interp) )); + // } REFTOTAL(interp)++; } @@ -2160,6 +2163,7 @@ _Py_NewReference(PyObject *op) { #ifdef Py_REF_DEBUG reftotal_increment(_PyInterpreterState_GET()); + state_change(op, 1, 1, op->ob_type->tp_name, _Py_GetGlobalRefTotal()); #endif new_reference(op); } diff --git a/Objects/structseq.c b/Objects/structseq.c index 2a5343815866d3..349fc2e713bdbf 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -592,7 +592,8 @@ _PyStructSequence_FiniType(PyTypeObject *type) // Don't use Py_DECREF(): static type must not be deallocated Py_SET_REFCNT(type, 0); #ifdef Py_REF_DEBUG - _Py_DecRefTotal(_PyInterpreterState_GET()); + _Py_DecRefTotal(_PyInterpreterState_GET()); + state_change(type, 0, -1, "type", _Py_GetGlobalRefTotal()); #endif // Make sure that _PyStructSequence_InitType() will initialize diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 61fab4078d66ba..6afdf4e42a5c17 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -945,6 +945,7 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) *pv = NULL; #ifdef Py_REF_DEBUG _Py_DecRefTotal(_PyInterpreterState_GET()); + state_change(v, 0, -1, "tuple", _Py_GetGlobalRefTotal()); #endif PyObject_GC_Del(v); return -1; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 9ea458f30394e3..cb69e88f848c6c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2152,7 +2152,6 @@ mro_implementation(PyTypeObject *type) return NULL; } - ; PyTuple_SET_ITEM(result, 0, Py_NewRef(type)); for (Py_ssize_t i = 0; i < k; i++) { PyObject *cls = PyTuple_GET_ITEM(base->tp_mro, i); diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 85e5ae735709fd..4ae8934f0ede8e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -56,6 +56,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "pycore_unicodeobject.h" // struct _Py_unicode_state #include "pycore_unicodeobject_generated.h" // _PyUnicode_InitStaticStrings() #include "stringlib/eq.h" // unicode_eq() +#include "object.h" #ifdef MS_WINDOWS #include @@ -968,7 +969,8 @@ resize_compact(PyObject *unicode, Py_ssize_t length) #ifdef Py_TRACE_REFS _Py_ForgetReference(unicode); #endif - + long old_refcnt = unicode->ob_refcnt; + state_change(unicode, 0, 0, "str", _Py_GetGlobalRefTotal()); new_unicode = (PyObject *)PyObject_Realloc(unicode, new_size); if (new_unicode == NULL) { _Py_NewReferenceNoTotal(unicode); @@ -976,6 +978,8 @@ resize_compact(PyObject *unicode, Py_ssize_t length) return NULL; } unicode = new_unicode; + state_change(unicode, old_refcnt, 0, "str", _Py_GetGlobalRefTotal()); + _Py_NewReferenceNoTotal(unicode); _PyUnicode_LENGTH(unicode) = length; @@ -1018,12 +1022,15 @@ resize_inplace(PyObject *unicode, Py_ssize_t length) _PyUnicode_UTF8(unicode) = NULL; _PyUnicode_UTF8_LENGTH(unicode) = 0; } - + long old_refcnt = unicode->ob_refcnt; + state_change(unicode, 0, 0, "str", _Py_GetGlobalRefTotal()); data = (PyObject *)PyObject_Realloc(data, new_size); if (data == NULL) { PyErr_NoMemory(); return -1; } + state_change(unicode, old_refcnt, 0, "str", _Py_GetGlobalRefTotal()); + _PyUnicode_DATA_ANY(unicode) = data; if (share_utf8) { _PyUnicode_UTF8(unicode) = data; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 4d693a1be1f89e..72f0a5f13bf900 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -36,6 +36,7 @@ Data members: #include "osdefs.h" // DELIM #include "stdlib_module_names.h" // _Py_stdlib_module_names #include +#include #ifdef MS_WINDOWS #define WIN32_LEAN_AND_MEAN @@ -1850,12 +1851,18 @@ sys_getrefcount_impl(PyObject *module, PyObject *object) sys.gettotalrefcount -> Py_ssize_t [clinic start generated code]*/ +extern void store_state(); +extern void check_with_stored_state(); + static Py_ssize_t sys_gettotalrefcount_impl(PyObject *module) /*[clinic end generated code: output=4103886cf17c25bc input=53b744faa5d2e4f6]*/ { /* It may make sense to return the total for the current interpreter or have a second function that does so. */ + check_with_stored_state(); + store_state(); + fprintf(stderr, "ref total %ld\n", _Py_GetGlobalRefTotal()); return _Py_GetGlobalRefTotal(); } diff --git a/cb.cpp b/cb.cpp new file mode 100644 index 00000000000000..a8af3d86633776 --- /dev/null +++ b/cb.cpp @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include + +static std::map current; +static std::map stored; +static std::map type_map; + +struct State { + long ref_cnt_diff; + void *original_ptr; + std::string type; +}; +std::vector flushed; +long total_ref = 0; + +void breakpoint() {} + +extern "C" { +extern void state_change(void *ptr, long rc, long diff, const char *type, + long current_total_ref); +extern void store_state(); +extern void check_with_stored_state(); + +extern void state_change(void *ptr, long rc, long diff, const char *type, + long current_total_ref) { + + total_ref += diff; + if (total_ref != current_total_ref) { + fprintf(stderr, "unexpected total ref. here: %ld (%+ld) there %ld\n", + total_ref, diff, current_total_ref); + total_ref = current_total_ref; + breakpoint(); + } + + if (rc < 0) + return; + + if (diff && current[ptr] && current[ptr] + diff != rc) { + fprintf(stderr, "unexpected ref count change of %p: %ld, %ld -> %ld\n", ptr, + diff, current[ptr], rc); + if (rc < 1000000) // immortal + breakpoint(); + } + + if (rc != 0) { + current[ptr] = rc; + type_map[ptr] = type; + return; + } + + if (stored[ptr]) + flushed.emplace_back(-stored[ptr], ptr, type_map[ptr]); + current.erase(ptr); + stored.erase(ptr); + type_map.erase(ptr); +} + +extern void store_state() { + stored = current; + flushed.clear(); +} +extern void check_with_stored_state() { + if (stored.size() == 0) + return; + + std::set diff; + std::map typed_diff; + + for (auto i : current) + if (stored[i.first] != i.second) + diff.insert(i.first); + + for (auto i : stored) + if (current[i.first] != i.second) + diff.insert(i.first); + + long rc_change = 0; + + for (auto i : diff) { + rc_change += current[i] - stored[i]; + typed_diff[type_map[i]] += current[i] - stored[i]; + } + + for (auto state : flushed) { + rc_change += state.ref_cnt_diff; + typed_diff[state.type] += state.ref_cnt_diff; + } + + for (auto it = typed_diff.begin(); it != typed_diff.end();) + if (it->second == 0) + it = typed_diff.erase(it); + else + ++it; + + if (typed_diff.empty()) + return; + + for (auto i : diff) + fprintf(stderr, "ref change of living %p (%s): %ld, %ld -> %ld\n", i, + type_map[i].c_str(), current[i] - stored[i], stored[i], current[i]); + + for (auto state : flushed) + fprintf(stderr, "ref change of died %p (%s): %ld\n", state.original_ptr, + state.type.c_str(), state.ref_cnt_diff); + + for (auto i : typed_diff) + fprintf(stderr, "ref change of type %s: %ld\n", i.first.c_str(), i.second); + + fprintf(stderr, "total ref change %ld\n", rc_change); +} +} \ No newline at end of file From 111be32109ec5ae40a77cfceb8785fbb8c7b3c1f Mon Sep 17 00:00:00 2001 From: sunmy2019 <59365878+sunmy2019@users.noreply.github.com> Date: Thu, 20 Apr 2023 21:35:37 +0800 Subject: [PATCH 2/3] fix crashing on uninitialized PyObjects --- Include/object.h | 2 +- cb.cpp | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Include/object.h b/Include/object.h index cfcff6361c4f1e..e986f038560583 100644 --- a/Include/object.h +++ b/Include/object.h @@ -169,7 +169,7 @@ static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) { static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) { - state_change(ob, refcnt, 0, get_type_name(ob->ob_type), _Py_GetGlobalRefTotal()); + state_change(ob, refcnt, 0, 0, _Py_GetGlobalRefTotal()); ob->ob_refcnt = refcnt; } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 diff --git a/cb.cpp b/cb.cpp index a8af3d86633776..6e355d16f0eda0 100644 --- a/cb.cpp +++ b/cb.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -42,16 +43,25 @@ extern void state_change(void *ptr, long rc, long diff, const char *type, if (diff && current[ptr] && current[ptr] + diff != rc) { fprintf(stderr, "unexpected ref count change of %p: %ld, %ld -> %ld\n", ptr, diff, current[ptr], rc); - if (rc < 1000000) // immortal + if (rc < 1000000) // not immortal breakpoint(); } if (rc != 0) { current[ptr] = rc; - type_map[ptr] = type; + // store type name early, so that we can print something when unexpected + // things happen + if (type) + type_map[ptr] = type; return; } + if (type) + type_map[ptr] = type; + else if (type_map[ptr].size() == 0) + type_map[ptr] = + "__UNKNOWN__"; // handles the case when PyObject is uninitialized + if (stored[ptr]) flushed.emplace_back(-stored[ptr], ptr, type_map[ptr]); current.erase(ptr); From c6ca259a10e93fb7f602f0aa3293ab2e6a181ee0 Mon Sep 17 00:00:00 2001 From: sunmy2019 <59365878+sunmy2019@users.noreply.github.com> Date: Thu, 20 Apr 2023 22:52:01 +0800 Subject: [PATCH 3/3] fix wrong pointer --- Objects/bytesobject.c | 4 ++-- Objects/dictobject.c | 10 +++++----- cb.cpp | 17 ++++++++++------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 9c6bcb71dcca54..1ca250769ab4c9 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -3065,7 +3065,7 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize) #endif long old_refcnt = v->ob_refcnt; - state_change(v, 0, 0, "PyDictKeysObject", _Py_GetGlobalRefTotal()); + state_change(v, 0, 0, "bytes", _Py_GetGlobalRefTotal()); *pv = (PyObject *) PyObject_Realloc(v, PyBytesObject_SIZE + newsize); @@ -3077,7 +3077,7 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize) PyErr_NoMemory(); return -1; } - state_change(pv, old_refcnt, 0, "PyDictKeysObject", _Py_GetGlobalRefTotal()); + state_change(*pv, old_refcnt, 0, "bytes", _Py_GetGlobalRefTotal()); _Py_NewReferenceNoTotal(*pv); sv = (PyBytesObject *) *pv; diff --git a/Objects/dictobject.c b/Objects/dictobject.c index fd29965c0403ff..9b06a3c08b15d0 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -305,7 +305,7 @@ dictkeys_incref(PyDictKeysObject *dk) { #ifdef Py_REF_DEBUG _Py_IncRefTotal(_PyInterpreterState_GET()); - state_change(dk, -1, +1, "PyDictKeysObject", _Py_GetGlobalRefTotal()); + state_change(dk, -1, +1, "__PyDictKeysObject", _Py_GetGlobalRefTotal()); #endif dk->dk_refcnt++; } @@ -316,7 +316,7 @@ dictkeys_decref(PyInterpreterState *interp, PyDictKeysObject *dk) assert(dk->dk_refcnt > 0); #ifdef Py_REF_DEBUG _Py_DecRefTotal(_PyInterpreterState_GET()); - state_change(dk, -1, -1, "PyDictKeysObject", _Py_GetGlobalRefTotal()); + state_change(dk, -1, -1, "__PyDictKeysObject", _Py_GetGlobalRefTotal()); #endif if (--dk->dk_refcnt == 0) { free_keys_object(interp, dk); @@ -637,7 +637,7 @@ new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode) } #ifdef Py_REF_DEBUG _Py_IncRefTotal(_PyInterpreterState_GET()); - state_change(dk, -1, +1, "PyDictKeysObject", _Py_GetGlobalRefTotal()); + state_change(dk, -1, +1, "__PyDictKeysObject", _Py_GetGlobalRefTotal()); #endif dk->dk_refcnt = 1; dk->dk_log2_size = log2_size; @@ -828,7 +828,7 @@ clone_combined_dict_keys(PyDictObject *orig) keys->dk_refcnt is already set to 1 (after memcpy). */ #ifdef Py_REF_DEBUG _Py_IncRefTotal(_PyInterpreterState_GET()); - state_change(keys, -1, +1, "PyDictKeysObject", _Py_GetGlobalRefTotal()); + state_change(keys, -1, +1, "__PyDictKeysObject", _Py_GetGlobalRefTotal()); #endif return keys; } @@ -1535,7 +1535,7 @@ dictresize(PyInterpreterState *interp, PyDictObject *mp, // are moved already. #ifdef Py_REF_DEBUG _Py_DecRefTotal(_PyInterpreterState_GET()); - state_change(oldkeys, -1, -1, "PyDictKeysObject", _Py_GetGlobalRefTotal()); + state_change(oldkeys, -1, -1, "__PyDictKeysObject", _Py_GetGlobalRefTotal()); #endif if (oldkeys == Py_EMPTY_KEYS) { oldkeys->dk_refcnt--; diff --git a/cb.cpp b/cb.cpp index 6e355d16f0eda0..9cbe33a18f0a35 100644 --- a/cb.cpp +++ b/cb.cpp @@ -26,9 +26,10 @@ extern void state_change(void *ptr, long rc, long diff, const char *type, extern void store_state(); extern void check_with_stored_state(); +const char *get_type_name(void *ptr) { return type_map[ptr].c_str(); } + extern void state_change(void *ptr, long rc, long diff, const char *type, long current_total_ref) { - total_ref += diff; if (total_ref != current_total_ref) { fprintf(stderr, "unexpected total ref. here: %ld (%+ld) there %ld\n", @@ -41,8 +42,10 @@ extern void state_change(void *ptr, long rc, long diff, const char *type, return; if (diff && current[ptr] && current[ptr] + diff != rc) { - fprintf(stderr, "unexpected ref count change of %p: %ld, %ld -> %ld\n", ptr, - diff, current[ptr], rc); + fprintf(stderr, + "unexpected ref count change of %p: %ld, (%s)%ld -> (%s)%ld,\n", + ptr, diff, type_map[ptr].c_str(), current[ptr], + type ? type : "__UNKNOWN__", rc); if (rc < 1000000) // not immortal breakpoint(); } @@ -110,16 +113,16 @@ extern void check_with_stored_state() { return; for (auto i : diff) - fprintf(stderr, "ref change of living %p (%s): %ld, %ld -> %ld\n", i, + fprintf(stderr, "ref change of living %p (%s): %+ld, %ld -> %ld\n", i, type_map[i].c_str(), current[i] - stored[i], stored[i], current[i]); for (auto state : flushed) - fprintf(stderr, "ref change of died %p (%s): %ld\n", state.original_ptr, + fprintf(stderr, "ref change of died %p (%s): %+ld\n", state.original_ptr, state.type.c_str(), state.ref_cnt_diff); for (auto i : typed_diff) - fprintf(stderr, "ref change of type %s: %ld\n", i.first.c_str(), i.second); + fprintf(stderr, "ref change of type %s: %+ld\n", i.first.c_str(), i.second); - fprintf(stderr, "total ref change %ld\n", rc_change); + fprintf(stderr, "total ref change %+ld\n", rc_change); } } \ No newline at end of file