Repository: nvaccess/nvda

Issue:
Failing to call super in plug-in constructor breaks script handling
**Reported by jteh on 2015-10-30 06:43**
@tspivy noted that failing to call super in a plug-in constructor completely breaks all script handling where the plug-in is queried. For global plug-ins, this means the entirety of NVDA.

I haven't tested this myself, but it makes sense. The ScriptableObject constructor is what sets _gestureMap and getScript assumes this is present. We should probably catch and log exceptions when calling gesture.script in InputManager.executeGesture, since we _really_ don't want that method throwing exceptions.



Discussion:
I'd say a p3 is ok for this, as this is causing problems for external contributions only? cc @jcsteh @michaeldcurran
Gave it a p3. Although serious when it happens,  the developer of the plugin would have surely noticed it when developing.

Resolving patch:
diff --git a/source/baseObject.py b/source/baseObject.py
--- a/source/baseObject.py
+++ b/source/baseObject.py
@@ -1,8 +1,7 @@
-#baseObject.py
-#A part of NonVisual Desktop Access (NVDA)
-#Copyright (C) 2007-2018 NV Access Limited, Christopher Toth, Babbage B.V.
-#This file is covered by the GNU General Public License.
-#See the file COPYING for more details.
+# A part of NonVisual Desktop Access (NVDA)
+# Copyright (C) 2007-2020 NV Access Limited, Christopher Toth, Babbage B.V., Julien Cochuyt
+# This file is covered by the GNU General Public License.
+# See the file COPYING for more details.
 
 """Contains the base classes that many of NVDA's classes such as NVDAObjects, virtualBuffers, appModules, synthDrivers inherit from. These base classes provide such things as auto properties, and methods and properties for scripting and key binding.
 """
@@ -283,6 +282,12 @@ def getScript(self,gesture):
 				return self._gestureMap[identifier].__get__(self, self.__class__)
 			except KeyError:
 				continue
+			except AttributeError:
+				log.exception((
+					"Base class may not have been initialized."
+					f"\nMRO={self.__class__.__mro__}"
+				) if not hasattr(self, "_gestureMap") else None)
+				return None
 		else:
 			return None
 
diff --git a/source/scriptHandler.py b/source/scriptHandler.py
--- a/source/scriptHandler.py
+++ b/source/scriptHandler.py
@@ -1,6 +1,6 @@
 # scriptHandler.py
 # A part of NonVisual Desktop Access (NVDA)
-# Copyright (C) 2007-2019 NV Access Limited, Babbage B.V.
+# Copyright (C) 2007-2020 NV Access Limited, Babbage B.V., Julien Cochuyt
 # This file is covered by the GNU General Public License.
 # See the file COPYING for more details.
 
@@ -54,8 +54,11 @@ def _getObjScript(obj, gesture, globalMapScripts):
 			except AttributeError:
 				pass
 
-	# Search the object itself for in-built bindings.
-	return obj.getScript(gesture)
+	try:
+		# Search the object itself for in-built bindings.
+		return obj.getScript(gesture)
+	except Exception:  # Prevent a faulty add-on from breaking script handling altogether (#5446)
+		log.exception()
 
 def findScript(gesture):
 	focus = api.getFocusObject()
@@ -281,4 +284,3 @@ def script_decorator(decoratedScript):
 			decoratedScript.resumeSayAllMode = resumeSayAllMode
 		return decoratedScript
 	return script_decorator
-


Test patch: