Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Potential crashes between source deletion and accessing source in the gui #906

Closed
sssoleileraaa opened this issue Mar 11, 2020 · 12 comments
Closed
Labels
bug Something isn't working sync sync issues for future epic

Comments

@sssoleileraaa
Copy link
Contributor

Description

If a sync comes back with deleted sources from the server we delete them locally and then call update_sources which will first remove all the source widgets then remove all the conversation widgets for those sources. If a message, reply, or file download job finishes before the source widget is destroyed then it will try to access source.uuid or source.collection in several places in the code and crash the app. I think there is also an issue with a user trying to open a file for the source at this time.

To prevent this type of crash we should only access the source db object when absolutely necessary. For instance, it's not necessary to store source on an object when we only need the uuid so we can find a source widget.

@eloquence eloquence changed the title Potentional crashes between source deletion and accessing source in the gui Potential crashes between source deletion and accessing source in the gui Mar 11, 2020
@sssoleileraaa
Copy link
Contributor Author

sssoleileraaa commented Mar 19, 2020

Here's a list of areas in the code that need attention regarding possible crashes due to trying to access data on a deleted source without catching the exception:

  1. ✔️DONE in delete source widgets for current sync update #1114
    SourceWidget.update raises exception and callers don't catch it causing the app to crash
  2. ✔️DONE in Fix starring behavior #952
    StarToggleButton
  3. DeleteSourceMessageBox:
    for submission in source.collection:
  4. ConversationView:
    self.update_conversation(self.source.collection)
  5. on_reply_sent:
    if source_uuid == self.source.uuid:
  6. SourceConversationWrapper:
    self.source_uuid = source.uuid
  7. on_source_change:
    self.source_conversations[source.uuid] = conversation_wrapper
  8. ✔️DONE in delete source widgets for current sync update #1114
  9. DeleteSourceMessageBox:
    for submission in source.collection:
  10. ReplyBox:
    if self.source.public_key:
  11. SourceProfileShortWidget:
    self.updated.setText(_(arrow.get(self.source.last_updated).format('DD MMM')))
  12. ✔️DONE in no longer access source db obj in snippet #964
    set_snippet
  13. ✔️DONE in delete source widgets for current sync update #1114
    schedule_source_management:
    self.source_widgets[source.uuid] = new_source

    Some of these links take you to areas of the code where there are multiple instances of the issue, so look around for source or file or other database objects widgets are accessing to make sure you get em all. Also I might have missed some in the list above. If you want to fix the issue for now by surrounding the code in a try-catch, that works, but it's more ideal if you can remove the db objects from the widgets.

@sssoleileraaa
Copy link
Contributor Author

Numbers: 1, 2, and 8 have PRs. The rest are still up for grabs.

@sssoleileraaa sssoleileraaa added the bug Something isn't working label Mar 24, 2020
@sssoleileraaa
Copy link
Contributor Author

sssoleileraaa commented Mar 26, 2020

Saw # 1 crasher in the list happen today:

Traceback (most recent call last):
  File "/home/creviera/workspace/freedomofpress/securedrop-client/securedrop_client/gui/widgets.py", line 1004, in schedule_source_management
    new_source = SourceWidget(self.controller, source)
  File "/home/creviera/workspace/freedomofpress/securedrop-client/securedrop_client/gui/widgets.py", line 1220, in __init__
    self.update()
  File "/home/creviera/workspace/freedomofpress/securedrop-client/securedrop_client/gui/widgets.py", line 1227, in update
    self.controller.session.refresh(self.source)
  File "/home/creviera/workspace/freedomofpress/securedrop-client/.venv/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 1675, in refresh
    "Could not refresh instance '%s'" % instance_str(instance)
sqlalchemy.exc.InvalidRequestError: Could not refresh instance '<Source at 0x7f04fd010790>'

@eloquence
Copy link
Member

eloquence commented Mar 27, 2020

We discussed today that a naive try/catch strategy around all UI access to widgets that may be tied to deleted database objects is probably the best first iteration to safeguard this. We'll likely not get to this before Monday, but it's one of the highest priority known areas that can cause crashes, so tracking as release blocker.

@eloquence eloquence added this to the 0.2.0 milestone Apr 1, 2020
@eloquence
Copy link
Member

Implementing the try/catch strategy mentioned above is a goal for the 4/2-4/15 sprint; the more comprehensive approach in #967 can be revisited at a later time.

@sssoleileraaa
Copy link
Contributor Author

(hit this again today after deleting some sources server-side and starting the client: #906 (comment))

@eloquence
Copy link
Member

Deferring to near-term backlog as it's not been a significant issue for pilot installs so far. We'll revisit this in the next sprint (after the current 4/22-5/6 sprint); given that we do know that there's crash potential here, I do think it should go into 0.2.1/0.3.0 at the latest.

@sssoleileraaa
Copy link
Contributor Author

We saw during the pilot that a new piece of code that was added after this issue was opened caused a segfault. The reason is that we access last_updated on the source db object without making sure it's valid:

my_ts = arrow.get(me.source.last_updated)
other_ts = arrow.get(them.source.last_updated)

This can be added as part of # 8 in the list above.

@eloquence eloquence modified the milestones: 0.2.0, 0.3.0 May 5, 2020
@eloquence
Copy link
Member

For the 6/3-6/17 sprint, @creviera has agreed to take a time-boxed stab at this to make an initial round of stability improvements, aiming for 8 hours (that should ideally include review, so I recommend making the implementation time-box shorter).

@sssoleileraaa
Copy link
Contributor Author

Update on the progress of this issue:

What's been fixed?

1. ✔️DONE in #1114
SourceWidget.update raises exception and callers don't catch it causing the app to crash

2. ✔️DONE in #952
StarToggleButton

8. ✔️DONE in #1114

12. ✔️DONE in #964
set_snippet

13. ✔️DONE in #1114
schedule_source_management:

self.source_widgets[source.uuid] = new_source

What's left?

3. DeleteSourceMessageBox:

for submission in source.collection:

4. ConversationView:
self.update_conversation(self.source.collection)

5. on_reply_sent:
if source_uuid == self.source.uuid:

6. SourceConversationWrapper:
self.source_uuid = source.uuid

7. on_source_change:
self.source_conversations[source.uuid] = conversation_wrapper

9. DeleteSourceMessageBox:
for submission in source.collection:

10. ReplyBox:
if self.source.public_key:

11. SourceProfileShortWidget:
self.updated.setText(_(arrow.get(self.source.last_updated).format('DD MMM')))

@eloquence
Copy link
Member

Thanks @creviera for the writeup. Since you've addressed the issues which were straightforward to reproduce and similar to reports we've heard from prod users, we've agreed to defer additional work on this for now, but will pick this issue up again and leave it open for tracking purposes.

@eloquence eloquence removed this from the 0.3.0 milestone Jun 24, 2020
@zenmonkeykstop zenmonkeykstop added the sync sync issues for future epic label Aug 15, 2024
@zenmonkeykstop
Copy link
Contributor

Closing, looks like it was addressed. May reopen as part of a future sync/data model milestone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working sync sync issues for future epic
Projects
None yet
Development

No branches or pull requests

3 participants