Repository: nvaccess/nvda

Issue:
wxYield called recursively
Probably fixed when #8679 is addressed.

### Steps to reproduce:
1. Open Firefox
2. Open a random page, e.g. the history of Germany wikipedia page.
3. With NVDA+ctrl+f, Search for test.
4. Press enter, and rapidly press up arrow after that.

### Actual behavior:
In many cases, I"m getting the following output in the log:

<details>
<summary>Log snippet</summary>
<pre>
error executing script: <bound method Gecko_ia2.script_moveByLine_forward of <virtualBuffers.gecko_ia2.Gecko_ia2 object at 0x0596B470>> with gesture u'down arrow'
Traceback (most recent call last):
  File "scriptHandler.pyc", line 187, in executeScript
  File "cursorManager.pyc", line 210, in script_moveByLine_forward
  File "cursorManager.pyc", line 140, in _caretMovementScriptHelper
  File "browseMode.pyc", line 1221, in _set_selection
  File "NVDAObjects\IAccessible\mozilla.pyc", line 51, in setFocus
  File "api.pyc", line 274, in processPendingEvents
wxAssertionError: C++ assertion "Assert failure" failed at ..\..\src\common\evtloopcmn.cpp(110) in wxEventLoopBase::Yield(): wxYield called recursively
</pre>
</details>

<details>
<summary>Similar error</summary>
<pre>
error executing event: caret on <baseObject.Dynamic_IAccessibleEditWindowNVDAObject object at 0x0551D890> with extra args of {}
Traceback (most recent call last):
  File "eventHandler.pyc", line 155, in executeEvent
  File "eventHandler.pyc", line 92, in __init__
  File "eventHandler.pyc", line 100, in next
  File "NVDAObjects\IAccessible\__init__.pyc", line 1373, in event_caret
  File "NVDAObjects\window\edit.pyc", line 792, in event_caret
  File "api.pyc", line 274, in processPendingEvents
wxAssertionError: C++ assertion "Assert failure" failed at ..\..\src\common\evtloopcmn.cpp(110) in wxEventLoopBase::Yield(): wxYield called recursively
</pre>
</details>

In some cases, it isn't even possible to read the log viewer's contents after opening too quickly after this error, and the error is repeated.

### Expected behavior:
No errors, and certainly not these.

### System configuration:

#### NVDA Installed/portable/running from source:
Installed

#### NVDA version:
alpha-16123

#### Windows version:
Windows 10 1803

#### Name and version of other software in use when reproducing the issue:
Firefox 62.0.2 X64

#### Other information about your system:
N/a

### Other questions:

#### Does the issue still occur after restarting your PC?
Yes

#### Have you tried any other versions of NVDA?
Yes. At least alpha-16103 had this too. I've never seen this before the merge of #8678, though



Discussion:
I assigned this p1 to investigate what's causing this. It looks pretty serious. Cc @michaeldcurran @josephsl @jcsteh @feerrenrut.
I've seen this too. I think it's due to the Mozilla setFocus code introduced in #8678. This gets executed by the cursorManager find code, which runs outside NVDA's event queue. It calls `api.processPendingEvents` to wait for a focus event, which in turn calls `wx.Yield`. But because this is outside NVDA's event queue, `wx.Yield` ends up running scripts/events from NVDA's queue. I guess the focus check code must be getting stuck in a loop.

Resolving patch:
diff --git a/source/browseMode.py b/source/browseMode.py
--- a/source/browseMode.py
+++ b/source/browseMode.py
@@ -10,6 +10,7 @@
 import time
 import weakref
 import wx
+import core
 from logHandler import log
 import documentBase
 import review
@@ -1042,7 +1043,9 @@ def move():
 				speech.cancelSpeech()
 				item.moveTo()
 				item.report()
-			wx.CallLater(100, move)
+			# We must use core.callLater rather than wx.CallLater to ensure that the callback runs within NVDA's core pump.
+			# If it didn't, and it directly or indirectly called wx.Yield, it could start executing NVDA's core pump from within the yield, causing recursion.
+			core.callLater(100, move)
 
 class BrowseModeDocumentTextInfo(textInfos.TextInfo):
 
diff --git a/source/cursorManager.py b/source/cursorManager.py
--- a/source/cursorManager.py
+++ b/source/cursorManager.py
@@ -10,6 +10,7 @@
 """
 
 import wx
+import core
 import baseObject
 import documentBase
 import gui
@@ -61,7 +62,9 @@ def __init__(self, parent, cursorManager, text, caseSensitivity):
 	def onOk(self, evt):
 		text = self.findTextField.GetValue()
 		caseSensitive = self.caseSensitiveCheckBox.GetValue()
-		wx.CallLater(100, self.activeCursorManager.doFindText, text, caseSensitive=caseSensitive)
+		# We must use core.callLater rather than wx.CallLater to ensure that the callback runs within NVDA's core pump.
+		# If it didn't, and it directly or indirectly called wx.Yield, it could start executing NVDA's core pump from within the yield, causing recursion.
+		core.callLater(100, self.activeCursorManager.doFindText, text, caseSensitive=caseSensitive)
 		self.Destroy()
 
 	def onCancel(self, evt):
diff --git a/source/globalCommands.py b/source/globalCommands.py
--- a/source/globalCommands.py
+++ b/source/globalCommands.py
@@ -1203,7 +1203,9 @@ def script_moveToParentTreeInterceptor(self,gesture):
 			parent.treeInterceptor.rootNVDAObject.setFocus()
 			import eventHandler
 			import wx
-			wx.CallLater(50,eventHandler.executeEvent,"gainFocus",parent.treeInterceptor.rootNVDAObject)
+			# We must use core.callLater rather than wx.CallLater to ensure that the callback runs within NVDA's core pump.
+			# If it didn't, and it directly or indirectly called wx.Yield, it could start executing NVDA's core pump from within the yield, causing recursion.
+			core.callLater(50,eventHandler.executeEvent,"gainFocus",parent.treeInterceptor.rootNVDAObject)
 	# Translators: Input help mode message for move to next document with focus command, mostly used in web browsing to move from embedded object to the webpage document.
 	script_moveToParentTreeInterceptor.__doc__=_("Moves the focus to the next closest document that contains the focus")
 	script_moveToParentTreeInterceptor.category=SCRCAT_FOCUS


Test patch: