What changed, and why it matters
This commit fixes an internal developer-only debugging tool (DebugMem) that crashes when scanning Python objects. The crash happens because some objects raise an AttributeError during Python's normal type-checking process. The fix simply catches that error and treats the object as not matching the requested type. The affected code is commented out by default and only used for memory-leak debugging, so it does not affect normal Electrum users or their wallets.
No security action required. Treat as a routine bug fix for an internal debugging utility. If reviewing, confirm DebugMem remains disabled by default and is not exposed to user-controlled input.
Security signals we found
Crash in non-production diagnostic helper
AttributeError swallowed during isinstance check
No input from untrusted sources
No cryptographic, network, or wallet logic changed
Evidence from the diff
DebugMem is a ThreadJob subclass used to count live instances of selected classes via gc.get_objects() and isinstance(). Some objects in the heap (specifically SimpleConfig, based on the traceback) implement getattribute to raise AttributeError aggressively, which breaks abc.instancecheck and causes the debug job to crash. The patch wraps isinstance() in a try/except AttributeError block and continues. Two GUI init files also update a commented-out example to add the job to plugins instead of network. The change is defensive and only affects an opt-in diagnostic path.
Changed components
electrum/util.py (DebugMem ThreadJob)electrum/gui/qml/__init__.py (commented example)electrum/gui/qt/__init__.py (commented example)Inspect captured patch +7 / −3
diff --git a/electrum/gui/qml/__init__.py b/electrum/gui/qml/__init__.py
index 1957e2a..8f7b668 100644
--- a/electrum/gui/qml/__init__.py
+++ b/electrum/gui/qml/__init__.py
@@ -59,7 +59,7 @@ class ElectrumGui(BaseElectrumGui, Logger):
self.logger.info("CWD=%s" % os.getcwd())
# Uncomment this call to verify objects are being properly
# GC-ed when windows are closed
- #network.add_jobs([DebugMem([Abstract_Wallet, SPV, Synchronizer,
+ #plugins.add_jobs([DebugMem([Abstract_Wallet, SPV, Synchronizer,
# ElectrumWindow], interval=5)])
if hasattr(Qt, "AA_ShareOpenGLContexts"):
diff --git a/electrum/gui/qt/__init__.py b/electrum/gui/qt/__init__.py
index dcd5092..4a37fb1 100644
--- a/electrum/gui/qt/__init__.py
+++ b/electrum/gui/qt/__init__.py
@@ -147,7 +147,7 @@ class ElectrumGui(BaseElectrumGui, Logger):
self.logger.info(f"Qt GUI starting up... Qt={QtCore.QT_VERSION_STR}, PyQt={QtCore.PYQT_VERSION_STR}")
# Uncomment this call to verify objects are being properly
# GC-ed when windows are closed
- #network.add_jobs([DebugMem([Abstract_Wallet, SPV, Synchronizer,
+ #plugins.add_jobs([DebugMem([Abstract_Wallet, SPV, Synchronizer,
# ElectrumWindow], interval=5)])
if hasattr(QtCore.Qt, "AA_ShareOpenGLContexts"):
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts)
diff --git a/electrum/util.py b/electrum/util.py
index 0a57b68..0bad5f5 100644
--- a/electrum/util.py
+++ b/electrum/util.py
@@ -365,7 +365,11 @@ class DebugMem(ThreadJob):
objmap = defaultdict(list)
for obj in gc.get_objects():
for class_ in self.classes:
- if isinstance(obj, class_):
+ try:
+ _isinstance = isinstance(obj, class_)
+ except AttributeError:
+ _isinstance = False
+ if _isinstance:
objmap[class_].append(obj)
for class_, objs in objmap.items():
self.logger.info(f"{class_.__name__}: {len(objs)}")
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.