Repository: nvaccess/nvda

Issue:
Restarting after a crash no longer works
<!-- Please read the text in this edit field before filling it in.
Please thoroughly read NVDA's wiki article on how to fill in this template, including how to provide the required files.
Issues may be closed if the required information is not present.
https://github.com/nvaccess/nvda/blob/master/devDocs/githubIssueTemplateExplanationAndExamples.md
Please also note that the NVDA project has a Citizen and Contributor Code of Conduct which can be found at https://github.com/nvaccess/nvda/blob/master/CODE_OF_CONDUCT.md. NV Access expects that all contributors and other community members read and abide by the rules set out in this document while participating or contributing to this project. This includes creating or commenting on issues and pull requests. 

Each of the questions and sections below start with multiple hash symbols (#). Place your answers and information on the blank line below each question.
-->

### Steps to reproduce:
1. Find a way to crash NVDA. I reproduced this reliably by crashing a synthesizer, but I don't think this is specific to that particular case.
### Actual behavior:
NVDA does not restart after the crash.
### Expected behavior:
NVDA should restart.
### System configuration
#### NVDA installed/portable/running from source:
Installed.
#### NVDA version:
alpha-23112,0d98162d
#### Windows version:
Windows 10, build 21390.2025
#### Name and version of other software in use when reproducing the issue:
N/A
#### Other information about your system:
N/a
### Other questions
#### Does the issue still occur after restarting your computer?
Yes
#### Have you tried any other versions of NVDA? If so, please report their behaviors.
Yes, 2020.4 works normally. This popped up somewhere around the time NVDA's exit process was refactored, I believe.
#### If add-ons are disabled, is your problem still occurring?
Yes.
#### Does the issue still occur after you run the COM Registration Fixing Tool in NVDA's tools menu?
Yes.


Discussion:
>  1. Find a way to crash NVDA. I reproduced this reliably by crashing a synthesizer, but I don't think this is specific to that particular case.
>   Actual behavior:
> NVDA does not restart after the crash.

I see that you said this "worked correctly" in 2020.4.
Can you please give exact steps to perform the crash you created?

Perhaps others know something about this feature, but I have experienced many NVDA crashes, from many causes, and if NVDA restarted on its own it was the exception rather than the rule.
This worked normally in 2020.4, but doesn't seem to work now. NVDA has 
been able to restart itself after some crashes since 2011.3.

On 6/17/2021 3:19 AM, Luke Davis wrote:
> > 1. Find a way to crash NVDA. I reproduced this reliably by crashing 
> a synthesizer, but I don't think this is specific to that particular case.
> > Actual behavior:
> > NVDA does not restart after the crash.
>
> What leads you to believe that NVDA should be expected to restart on its
> own after a runtime crash such as this?
>
> When (under what version) did that ever work?
>
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub 
> <https://github.com/nvaccess/nvda/issues/12557#issuecomment-862996071>, 
> or unsubscribe 
> <https://github.com/notifications/unsubscribe-auth/ADY4AYDFECWN7HDZZ4WK7W3TTGOZLANCNFSM463AZAOA>.
>

@Mohamed00 we really need specific details. Ideally also a log and crash dump.
The crash occurred in the SAPI4 version of ViaVoice. It's a bug in the synthesizer, but NVDA was previously able to reliably restart after a crash like this. However, in recent builds, it doesn't restart anymore. 
[log and crash dump](https://github.com/nvaccess/nvda/files/6674332/logs.zip)
Sorry, accidentally broke the link. It's fixed now.

Resolving patch:
diff --git a/source/core.py b/source/core.py
--- a/source/core.py
+++ b/source/core.py
@@ -120,6 +120,36 @@ class NewNVDAInstance:
 	directory: Optional[str] = None
 
 
+def restartUnsafely():
+	"""Start a new copy of NVDA immediately.
+	Used as a last resort, in the event of a serious error to immediately restart NVDA without running any
+	cleanup / exit code.
+	There is no dependency on NVDA currently functioning correctly, which is in contrast with L{restart} which
+	depends on the internal queue processing (queueHandler).
+	Because none of NVDA's shutdown code is run, NVDA is likely to be left in an unclean state.
+	Some examples of clean up that may be skipped.
+	- Free NVDA's mutex (mutex prevents multiple NVDA instances), leaving it abandoned when this process ends.
+	  - However, this situation is handled during mutex acquisition.
+	- Remove icons (systray)
+	- Saving settings
+	"""
+
+	import subprocess
+	for paramToRemove in ("--ease-of-access"):
+		try:
+			sys.argv.remove(paramToRemove)
+		except ValueError:
+			pass
+	options = []
+	if not hasattr(sys, "frozen"):
+		options.append(os.path.basename(sys.argv[0]))
+	_startNewInstance(NewNVDAInstance(
+		sys.executable,
+		subprocess.list2cmdline(options + sys.argv[1:]),
+		globalVars.appDir
+	))
+
+
 def restart(disableAddons=False, debugLogging=False):
 	"""Restarts NVDA by starting a new copy."""
 	if globalVars.appArgs.launcher:
diff --git a/source/watchdog.py b/source/watchdog.py
--- a/source/watchdog.py
+++ b/source/watchdog.py
@@ -1,8 +1,7 @@
-#watchdog.py
-#A part of NonVisual Desktop Access (NVDA)
-#Copyright (C) 2008-2016 NV Access Limited
-#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) 2008-2021 NV Access Limited
+# This file is covered by the GNU General Public License.
+# See the file COPYING for more details.
 
 import sys
 import os
@@ -214,7 +213,8 @@ def _crashHandler(exceptionInfo):
 	log.info(f"Listing stacks for Python threads:\n{stacks}")
 
 	log.info("Restarting due to crash")
-	core.restart()
+	# if NVDA has crashed we cannot rely on the queue handler to start the new NVDA instance
+	core.restartUnsafely()
 	return 1 # EXCEPTION_EXECUTE_HANDLER
 
 @ctypes.WINFUNCTYPE(None)


Test patch: