Repository: qutebrowser/qutebrowser

Issue:
objreg KeyError when pressing ctrl-c with config error
With e.g. `doesnotexist = true` in the config, we get the config error box, as expected.

When pressing `Ctrl-C` with that error open, we get a crash however:

```
10:48:14 DEBUG    init       app:_init_modules:398 Initializing config...
10:48:14 DEBUG    init       ini:__init__:56 Reading config from /home/florian/.config/qutebrowser/qutebrowser.conf
10:48:14 ERROR    init       config:_init_main_config:147 No option 'doesnotexist' in section 'colors'
Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 767, in set
    sect.setv(layer, optname, value, interpolated)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/sections.py", line 128, in setv
    self.values[key].setv(layer, value, interpolated)
KeyError: 'doesnotexist'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 145, in _init_main_config
    args.relaxed_config, parent=parent)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 380, in __init__
    self._from_cp(parser, relaxed)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 503, in _from_cp
    self._from_cp_section(sectname, cp, relaxed)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 529, in _from_cp_section
    self.set('conf', sectname, k, v, validate=False)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 769, in set
    raise configexc.NoOptionError(optname, sectname)
qutebrowser.config.configexc.NoOptionError: No option 'doesnotexist' in section 'colors'
10:48:14 DEBUG    misc       app:on_focus_object_changed:756 Focus object changed: <PyQt5.QtWidgets.QPushButton object at 0x7fce4d83e3a8>
10:48:14 DEBUG    misc       app:on_focus_object_changed:756 Focus object changed: <PyQt5.QtWidgets.QPushButton object at 0x7fce4d83e3a8>
10:48:14 DEBUG    misc       app:on_focus_object_changed:756 Focus object changed: None

(Pressing Ctrl-C)

10:48:15 DEBUG    destroy    crashsignal:handle_signal_wakeup:349 Handling signal wakeup!
10:48:15 INFO     destroy    error:handle_fatal_exc:69 SIGINT/SIGTERM received, shutting down!
10:48:15 INFO     destroy    error:handle_fatal_exc:69 Do the same again to forcefully quit.
10:48:15 DEBUG    destroy    app:shutdown:631 Shutting down with status 130, session None...
10:48:15 ERROR    misc       crashsignal:exception_hook:211 Uncaught exception
Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 767, in set
    sect.setv(layer, optname, value, interpolated)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/sections.py", line 128, in setv
    self.values[key].setv(layer, value, interpolated)
KeyError: 'doesnotexist'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 145, in _init_main_config
    args.relaxed_config, parent=parent)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 380, in __init__
    self._from_cp(parser, relaxed)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 503, in _from_cp
    self._from_cp_section(sectname, cp, relaxed)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 529, in _from_cp_section
    self.set('conf', sectname, k, v, validate=False)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 769, in set
    raise configexc.NoOptionError(optname, sectname)
qutebrowser.config.configexc.NoOptionError: No option 'doesnotexist' in section 'colors'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/app.py", line 633, in shutdown
    session_manager = objreg.get('session-manager')
  File "/home/florian/proj/qutebrowser/git/qutebrowser/utils/objreg.py", line 217, in get
    return reg[name]
  File "/home/florian/proj/qutebrowser/git/.venv/lib/python3.4/collections/__init__.py", line 884, in __getitem__
    raise KeyError(key)
KeyError: 'session-manager'
10:48:15 ERROR    destroy    crashsignal:_get_exception_info:187 Error while getting history: {}
Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 767, in set
    sect.setv(layer, optname, value, interpolated)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/sections.py", line 128, in setv
    self.values[key].setv(layer, value, interpolated)
KeyError: 'doesnotexist'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 145, in _init_main_config
    args.relaxed_config, parent=parent)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 380, in __init__
    self._from_cp(parser, relaxed)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 503, in _from_cp
    self._from_cp_section(sectname, cp, relaxed)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 529, in _from_cp_section
    self.set('conf', sectname, k, v, validate=False)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 769, in set
    raise configexc.NoOptionError(optname, sectname)
qutebrowser.config.configexc.NoOptionError: No option 'doesnotexist' in section 'colors'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/misc/crashsignal.py", line 185, in _get_exception_info
    cmd_history = objreg.get('command-history')[-5:]
  File "/home/florian/proj/qutebrowser/git/qutebrowser/utils/objreg.py", line 217, in get
    return reg[name]
  File "/home/florian/proj/qutebrowser/git/.venv/lib/python3.4/collections/__init__.py", line 884, in __getitem__
    raise KeyError(key)
KeyError: 'command-history'
10:48:15 ERROR    misc       crashdialog:__init__:159 Failed to get contact information!
Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 767, in set
    sect.setv(layer, optname, value, interpolated)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/sections.py", line 128, in setv
    self.values[key].setv(layer, value, interpolated)
KeyError: 'doesnotexist'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 145, in _init_main_config
    args.relaxed_config, parent=parent)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 380, in __init__
    self._from_cp(parser, relaxed)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 503, in _from_cp
    self._from_cp_section(sectname, cp, relaxed)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 529, in _from_cp_section
    self.set('conf', sectname, k, v, validate=False)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 769, in set
    raise configexc.NoOptionError(optname, sectname)
qutebrowser.config.configexc.NoOptionError: No option 'doesnotexist' in section 'colors'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/misc/crashdialog.py", line 153, in __init__
    state = objreg.get('state-config')
  File "/home/florian/proj/qutebrowser/git/qutebrowser/utils/objreg.py", line 217, in get
    return reg[name]
  File "/home/florian/proj/qutebrowser/git/.venv/lib/python3.4/collections/__init__.py", line 884, in __getitem__
    raise KeyError(key)
KeyError: 'state-config'
10:48:15 ERROR    misc       crashdialog:_init_checkboxes:430 Error while checking private browsing mode
Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 767, in set
    sect.setv(layer, optname, value, interpolated)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/sections.py", line 128, in setv
    self.values[key].setv(layer, value, interpolated)
KeyError: 'doesnotexist'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 145, in _init_main_config
    args.relaxed_config, parent=parent)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 380, in __init__
    self._from_cp(parser, relaxed)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 503, in _from_cp
    self._from_cp_section(sectname, cp, relaxed)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 529, in _from_cp_section
    self.set('conf', sectname, k, v, validate=False)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 769, in set
    raise configexc.NoOptionError(optname, sectname)
qutebrowser.config.configexc.NoOptionError: No option 'doesnotexist' in section 'colors'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/misc/crashdialog.py", line 427, in _init_checkboxes
    if config.get('general', 'private-browsing'):
  File "/home/florian/proj/qutebrowser/git/qutebrowser/config/config.py", line 128, in get
    return objreg.get('config').get(*args, **kwargs)
  File "/home/florian/proj/qutebrowser/git/qutebrowser/utils/objreg.py", line 217, in get
    return reg[name]
  File "/home/florian/proj/qutebrowser/git/.venv/lib/python3.4/collections/__init__.py", line 884, in __getitem__
    raise KeyError(key)
KeyError: 'config'
```



Discussion:

Resolving patch:
diff --git a/qutebrowser/app.py b/qutebrowser/app.py
--- a/qutebrowser/app.py
+++ b/qutebrowser/app.py
@@ -340,8 +340,9 @@ def _open_quickstart(args):
 
 def _save_version():
     """Save the current version to the state config."""
-    state_config = objreg.get('state-config')
-    state_config['general']['version'] = qutebrowser.__version__
+    state_config = objreg.get('state-config', None)
+    if state_config is not None:
+        state_config['general']['version'] = qutebrowser.__version__
 
 
 def on_focus_changed(_old, new):
@@ -647,14 +648,14 @@ def shutdown(self, status=0, session=None, last_window=False,
         self._shutting_down = True
         log.destroy.debug("Shutting down with status {}, session {}...".format(
             status, session))
-
-        session_manager = objreg.get('session-manager')
-        if session is not None:
-            session_manager.save(session, last_window=last_window,
-                                 load_next_time=True)
-        elif config.get('general', 'save-session'):
-            session_manager.save(sessions.default, last_window=last_window,
-                                 load_next_time=True)
+        session_manager = objreg.get('session-manager', None)
+        if session_manager is not None:
+            if session is not None:
+                session_manager.save(session, last_window=last_window,
+                                     load_next_time=True)
+            elif config.get('general', 'save-session'):
+                session_manager.save(sessions.default, last_window=last_window,
+                                     load_next_time=True)
 
         if prompt.prompt_queue.shutdown():
             # If shutdown was called while we were asking a question, we're in
@@ -680,7 +681,9 @@ def _shutdown(self, status, restart):
         # Remove eventfilter
         try:
             log.destroy.debug("Removing eventfilter...")
-            qApp.removeEventFilter(objreg.get('event-filter'))
+            event_filter = objreg.get('event-filter', None)
+            if event_filter is not None:
+                qApp.removeEventFilter(event_filter)
         except AttributeError:
             pass
         # Close all windows
@@ -722,7 +725,9 @@ def _shutdown(self, status, restart):
         # Now we can hopefully quit without segfaults
         log.destroy.debug("Deferring QApplication::exit...")
         objreg.get('signal-handler').deactivate()
-        objreg.get('session-manager').delete_autosave()
+        session_manager = objreg.get('session-manager', None)
+        if session_manager is not None:
+            session_manager.delete_autosave()
         # We use a singleshot timer to exit here to minimize the likelihood of
         # segfaults.
         QTimer.singleShot(0, functools.partial(qApp.exit, status))
diff --git a/qutebrowser/misc/crashsignal.py b/qutebrowser/misc/crashsignal.py
--- a/qutebrowser/misc/crashsignal.py
+++ b/qutebrowser/misc/crashsignal.py
@@ -171,14 +171,14 @@ def _get_exception_info(self):
         """
         try:
             pages = self._recover_pages(forgiving=True)
-        except Exception:
-            log.destroy.exception("Error while recovering pages")
+        except Exception as e:
+            log.destroy.exception("Error while recovering pages: {}".format(e))
             pages = []
 
         try:
             cmd_history = objreg.get('command-history')[-5:]
-        except Exception:
-            log.destroy.exception("Error while getting history: {}")
+        except Exception as e:
+            log.destroy.exception("Error while getting history: {}".format(e))
             cmd_history = []
 
         try:


Test patch: