Browse Source

qt wizard: make "GoBack" unroll the call stack to avoid stack overflow

fixes #6069
hard-fail-on-bad-server-string
SomberNight 5 years ago
parent
commit
f13f46c555
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 17
      electrum/base_wizard.py
  2. 32
      electrum/gui/qt/installwizard.py

17
electrum/base_wizard.py

@ -113,18 +113,21 @@ class BaseWizard(Logger):
def can_go_back(self): def can_go_back(self):
return len(self._stack) > 1 return len(self._stack) > 1
def go_back(self): def go_back(self, *, rerun_previous: bool = True) -> None:
if not self.can_go_back(): if not self.can_go_back():
return return
# pop 'current' frame # pop 'current' frame
self._stack.pop() self._stack.pop()
# pop 'previous' frame prev_frame = self._stack[-1]
stack_item = self._stack.pop()
# try to undo side effects since we last entered 'previous' frame # try to undo side effects since we last entered 'previous' frame
# FIXME only self.storage is properly restored # FIXME only self.data is properly restored
self.data = copy.deepcopy(stack_item.db_data) self.data = copy.deepcopy(prev_frame.db_data)
# rerun 'previous' frame
self.run(stack_item.action, *stack_item.args, **stack_item.kwargs) if rerun_previous:
# pop 'previous' frame
self._stack.pop()
# rerun 'previous' frame
self.run(prev_frame.action, *prev_frame.args, **prev_frame.kwargs)
def reset_stack(self): def reset_stack(self):
self._stack = [] self._stack = []

32
electrum/gui/qt/installwizard.py

@ -96,19 +96,27 @@ def wizard_dialog(func):
def func_wrapper(*args, **kwargs): def func_wrapper(*args, **kwargs):
run_next = kwargs['run_next'] run_next = kwargs['run_next']
wizard = args[0] # type: InstallWizard wizard = args[0] # type: InstallWizard
wizard.back_button.setText(_('Back') if wizard.can_go_back() else _('Cancel')) while True:
try: wizard.back_button.setText(_('Back') if wizard.can_go_back() else _('Cancel'))
out = func(*args, **kwargs) # current dialog
if type(out) is not tuple: try:
out = (out,) out = func(*args, **kwargs)
run_next(*out) if type(out) is not tuple:
except GoBack: out = (out,)
if wizard.can_go_back(): except GoBack:
wizard.go_back() if not wizard.can_go_back():
return wizard.close()
else: # to go back from the current dialog, we just let the caller unroll the stack:
wizard.close()
raise raise
# next dialog
try:
run_next(*out)
except GoBack:
# to go back from the next dialog, we ask the wizard to restore state
wizard.go_back(rerun_previous=False)
# and we re-run the current dialog (by continuing)
else:
break
return func_wrapper return func_wrapper

Loading…
Cancel
Save