SUPERCILEX / gnome-clipboard-history

Gnome Clipboard History is a clipboard manager Gnome extension that saves what you've copied into an easily accessible, searchable history panel.
https://extensions.gnome.org/extension/4839/clipboard-history/
MIT License
455 stars 45 forks source link

Gnome crashes on deletion of last entry #173

Open schlagmichdoch opened 3 months ago

schlagmichdoch commented 3 months ago

Describe the bug

When I manually clear all entries from the list, Gnome crashes and my session is restarted. When deleting single entries errors are logged.

How To Reproduce

  1. Copy multiple items to create multiple entries.
  2. Delete all icons via DEL until no entries are left.
  3. Gnome crashes
#### Versions
GNOME Shell 46.0
GCH   Version: 42
org.gnome.shell.extensions.clipboard-history cache-only-favorites false
org.gnome.shell.extensions.clipboard-history cache-size 100
org.gnome.shell.extensions.clipboard-history clear-history @as []
org.gnome.shell.extensions.clipboard-history confirm-clear true
org.gnome.shell.extensions.clipboard-history disable-down-arrow true
org.gnome.shell.extensions.clipboard-history display-mode 0
org.gnome.shell.extensions.clipboard-history enable-keybindings true
org.gnome.shell.extensions.clipboard-history history-size 1000
org.gnome.shell.extensions.clipboard-history move-item-first true
org.gnome.shell.extensions.clipboard-history next-entry @as []
org.gnome.shell.extensions.clipboard-history notify-on-copy false
org.gnome.shell.extensions.clipboard-history paste-on-selection true
org.gnome.shell.extensions.clipboard-history prev-entry @as []
org.gnome.shell.extensions.clipboard-history private-mode false
org.gnome.shell.extensions.clipboard-history process-primary-selection false
org.gnome.shell.extensions.clipboard-history strip-text false
org.gnome.shell.extensions.clipboard-history toggle-menu ['<Super>v']
org.gnome.shell.extensions.clipboard-history toggle-private-mode ['<Super><Shift>P']
org.gnome.shell.extensions.clipboard-history topbar-preview-size 10
org.gnome.shell.extensions.clipboard-history window-width-percentage 33

Additional context (if a crash, provide stack trace)

Log after deletion of a single entry:

Jun 16 15:19:52 U23 gnome-shell[18823]: Failed to create new MetaSelectionSourceMemory: Failed to create MetaAnonymousFile
Jun 16 15:19:52 U23 gnome-shell[18823]: Failed to create new MetaSelectionSourceMemory: Failed to create MetaAnonymousFile
Jun 16 15:19:52 U23 gnome-shell[18823]: Object .Gjs_ui_popupMenu_PopupMenuItem (0x5aed190d4cb0), has been already disposed — impossible to access it. This might be caused by the object having been destroyed from C code using something such as destroy(), dispose(), or remove() vfuncs.
                                        == Stack trace for context 0x5aed187b5c80 ==
                                        #0   5aed188789f8 i   resource:///org/gnome/shell/ui/popupMenu.js:153 (f6baa8f1330 @ 102)
                                        #1   5aed18878968 i   resource:///org/gnome/shell/ui/init.js:21 (f6baa870bf0 @ 48)

Log after deleting the last entries which resulted in a crash of gnome:

Jun 16 15:02:14 U23 gnome-shell[3618]: Object .Gjs_ui_popupMenu_PopupMenuItem (0x63bf7f2c1010), has been already disposed — impossible to access it. This might be caused by the object having been destroyed from C code using something such as destroy(), dispose(), or remove() vfuncs.
                                       == Stack trace for context 0x63bf7a3c2d50 ==
                                       #0   7ffc82a52b10 b   resource:///org/gnome/shell/ui/popupMenu.js:153 (295d160f1330 @ 102)
                                       #1   63bf7a48a8f8 i   resource:///org/gnome/shell/ui/init.js:21 (295d16070bf0 @ 48)
Jun 16 15:02:14 U23 gnome-shell[3618]: Failed to create new MetaSelectionSourceMemory: Failed to create MetaAnonymousFile
Jun 16 15:02:14 U23 gnome-shell[3618]: Failed to create new MetaSelectionSourceMemory: Failed to create MetaAnonymousFile
Jun 16 15:02:14 U23 gnome-shell[3618]: Object .Gjs_ui_popupMenu_PopupMenuItem (0x63bf7d045bb0), has been already disposed — impossible to access it. This might be caused by the object having been destroyed from C code using something such as destroy(), dispose(), or remove() vfuncs.
                                       == Stack trace for context 0x63bf7a3c2d50 ==
                                       #0   7ffc82a52b10 b   resource:///org/gnome/shell/ui/popupMenu.js:153 (295d160f1330 @ 102)
                                       #1   63bf7a48a8f8 i   resource:///org/gnome/shell/ui/init.js:21 (295d16070bf0 @ 48)
Jun 16 15:02:15 U23 gnome-shell[3618]: Object .Gjs_ui_popupMenu_PopupMenuItem (0x63bf7d057fe0), has been already disposed — impossible to access it. This might be caused by the object having been destroyed from C code using something such as destroy(), dispose(), or remove() vfuncs.
                                       == Stack trace for context 0x63bf7a3c2d50 ==
                                       #0   7ffc82a52d30 b   file:///home/USER/.local/share/gnome-shell/extensions/clipboard-history@alexsaveau.dev/extension.js:464 (1c07aa563f10 @ 210)
                                       #1   7ffc82a52df0 b   file:///home/USER/.local/share/gnome-shell/extensions/clipboard-history@alexsaveau.dev/extension.js:384 (1c07aa563d80 @ 25)
                                       #2   63bf7a48a8f8 i   resource:///org/gnome/shell/ui/init.js:21 (295d16070bf0 @ 48)
Jun 16 15:02:15 U23 gnome-shell[3618]: Object .Gjs_ui_popupMenu_PopupMenuItem (0x63bf7d057fe0), has been already disposed — impossible to access it. This might be caused by the object having been destroyed from C code using something such as destroy(), dispose(), or remove() vfuncs.
                                       == Stack trace for context 0x63bf7a3c2d50 ==
                                       #0   7ffc82a517a0 b   resource:///org/gnome/shell/ui/searchController.js:192 (3671d80d88d0 @ 61)
                                       #1   7ffc82a52d30 b   file:///home/USER/.local/share/gnome-shell/extensions/clipboard-history@alexsaveau.dev/extension.js:464 (1c07aa563f10 @ 210)
                                       #2   7ffc82a52df0 b   file:///home/USER/.local/share/gnome-shell/extensions/clipboard-history@alexsaveau.dev/extension.js:384 (1c07aa563d80 @ 25)
                                       #3   63bf7a48a8f8 i   resource:///org/gnome/shell/ui/init.js:21 (295d16070bf0 @ 48)
Jun 16 15:02:15 U23 gnome-shell[3618]: Object .Gjs_ui_popupMenu_PopupMenuItem (0x63bf7d057fe0), has been already disposed — impossible to access it. This might be caused by the object having been destroyed from C code using something such as destroy(), dispose(), or remove() vfuncs.
                                       == Stack trace for context 0x63bf7a3c2d50 ==
                                       #0   7ffc82a517a0 b   resource:///org/gnome/shell/ui/searchController.js:193 (3671d80d88d0 @ 95)
                                       #1   7ffc82a52d30 b   file:///home/USER/.local/share/gnome-shell/extensions/clipboard-history@alexsaveau.dev/extension.js:464 (1c07aa563f10 @ 210)
                                       #2   7ffc82a52df0 b   file:///home/USER/.local/share/gnome-shell/extensions/clipboard-history@alexsaveau.dev/extension.js:384 (1c07aa563d80 @ 25)
                                       #3   63bf7a48a8f8 i   resource:///org/gnome/shell/ui/init.js:21 (295d16070bf0 @ 48)
Jun 16 15:02:15 U23 gnome-shell[3618]: Object .Gjs_ui_popupMenu_PopupMenuItem (0x63bf7d057fe0), has been already disposed — impossible to access it. This might be caused by the object having been destroyed from C code using something such as destroy(), dispose(), or remove() vfuncs.
                                       == Stack trace for context 0x63bf7a3c2d50 ==
                                       #0   7ffc82a51920 b   resource:///org/gnome/shell/ui/popupMenu.js:1447 (295d160f7c90 @ 110)
                                       #1   7ffc82a519e0 b   resource:///org/gnome/shell/ui/popupMenu.js:1388 (295d160f7ba0 @ 80)
                                       #2   7ffc82a52d30 b   file:///home/USER/.local/share/gnome-shell/extensions/clipboard-history@alexsaveau.dev/extension.js:464 (1c07aa563f10 @ 210)
                                       #3   7ffc82a52df0 b   file:///home/USER/.local/share/gnome-shell/extensions/clipboard-history@alexsaveau.dev/extension.js:384 (1c07aa563d80 @ 25)
                                       #4   63bf7a48a8f8 i   resource:///org/gnome/shell/ui/init.js:21 (295d16070bf0 @ 48)
Jun 16 15:02:15 U23 gnome-shell[3618]: Failed to create new MetaSelectionSourceMemory: Failed to create MetaAnonymousFile
Jun 16 15:02:15 U23 gnome-shell[3618]: Failed to create new MetaSelectionSourceMemory: Failed to create MetaAnonymousFile
Jun 16 15:02:15 U23 gnome-shell[3618]: Object .Gjs_ui_popupMenu_PopupMenuItem (0x63bf7d04ecd0), has been already disposed — impossible to access it. This might be caused by the object having been destroyed from C code using something such as destroy(), dispose(), or remove() vfuncs.
                                       == Stack trace for context 0x63bf7a3c2d50 ==
                                       #0   7ffc82a52b10 b   resource:///org/gnome/shell/ui/popupMenu.js:153 (295d160f1330 @ 102)
                                       #1   63bf7a48a8f8 i   resource:///org/gnome/shell/ui/init.js:21 (295d16070bf0 @ 48)
Jun 16 15:02:17 U23 gnome-shell[3618]: clutter_actor_contains: assertion 'CLUTTER_IS_ACTOR (descendant)' failed
Jun 16 15:02:17 U23 gnome-shell[3618]: clutter_actor_contains: assertion 'CLUTTER_IS_ACTOR (descendant)' failed
Jun 16 15:02:17 U23 gnome-shell[3618]: GNOME Shell crashed with signal 11
SUPERCILEX commented 3 months ago

I'll be honest, those warnings have been there since forever and I have no idea what causes them. I couldn't repro the shell crash on Gnome 42.9, so maybe this is a Gnome bug? Might be worth filing a ticket with them to see what they say or at least if they know what could cause the PopupMenuItem warnings.

schlagmichdoch commented 3 months ago

Well I cannot reproduce the crash anymore, maybe this was a Gnome bug after all. Thanks for your quick response!

The rest of the behavior is still weird though: When deleting all entries manually, deleting the last entry simply resets the entries to the state before I started manually deleting them.

Understanding that, I took a look at your database.log file: Why are there still strings present that I have deleted a long time ago? This file should always only include the items that are currently in the clipboard history. If I delete an item from the clipboard history manually it should not be saved anywhere anymore.

What does this file do anyway? Is it for clipboard persistence on restart?

Seemingly this file is only flushed once I clear the clipboard history via the trash icon which than handles the extension unusable though as no new entries are added to the clipboard history.

SUPERCILEX commented 3 months ago

unusable though as no new entries are added to the clipboard history.

Hmmm, I think things might be very broken either on the Gnome 46 version of the extension or Gnome 46 itself. All of this works fine on my version.

Why are there still strings present that I have deleted a long time ago? This file should always only include the items that are currently in the clipboard history. If I delete an item from the clipboard history manually it should not be saved anywhere anymore.

What does this file do anyway? Is it for clipboard > persistence on restart?

That file is the entire database, so yeah persistant storage. Old strings are deleted eventually when you've hit a garbage collection threshold. To see this in action, favorite and unfavorite an entry like 500 times lol and it'll trigger. Or copy two entries back and forth. Or hit the space limit... Lots of reasons. Here's a detailed explanation: https://alexsaveau.dev/blog/projects/performance/clipboard/gnome/gch/gnome-clipboard-history

schlagmichdoch commented 3 months ago

Hmmm, I think things might be very broken either on the Gnome 46 version of the extension or Gnome 46 itself. All of this works fine on my version

Hm okay. I’ll keep an eye on updates. Until then, I’ll just use the clear item for the last entry.

Old strings are deleted eventually when you've hit a garbage collection threshold.

Thanks for the explanation and the link to your blog entry. Interesting stuff!

Anyways I expected the data to be gone if I deleted it from the entries table. If I copy passwords or alike I do not want to have them stored in a database somewhere after deletion.

If I understand it correctly, this would be the case if we would trigger compaction manually. How about a setting to trigger compaction whenever an entry is deleted? How much would that impact performance?

On another note, can I trigger the private mode toggle via a command as well or is this only possible via shortcut? If that’s possible maybe I could trigger the private mode automatically before copying an entry from my psw manager

SUPERCILEX commented 3 months ago

If I copy passwords or alike I do not want to have them stored in a database somewhere after deletion.

Yeah, my policy here is that you either need to turn on private mode before copying passwords or accept that whatever is in the clipboard doesn't have any security guarantees.

If I understand it correctly, this would be the case if we would trigger compaction manually. How about a setting to trigger compaction whenever an entry is deleted? How much would that impact performance?

The problem is that I don't want somebody to be going through deleting multiple items with a large clipboard (say multiple MBs) and everytime they click the button the UI freezes for a bit because we're regenerating a muli MB file. I could add a button somewhere that does compaction. Or maybe if you Ctrl click delete an entry that'll run compaction?

On another note, can I trigger the private mode toggle via a command as well or is this only possible via shortcut?

Sadly only via shortcut, though maybe this would work? https://github.com/jordansissel/xdotool#sending-keys You trigger the shortcut via CLI before password copy, then trigger it again to reopen the clipboard.

schlagmichdoch commented 2 months ago

Yeah, my policy here is that you either need to turn on private mode before copying passwords or accept that whatever is in the clipboard doesn't have any security guarantees

Ok, thanks for clarifying.

The problem is that I don't want somebody to be going through deleting multiple items with a large clipboard (say multiple MBs) and everytime they click the button the UI freezes for a bit because we're regenerating a muli MB file. I could add a button somewhere that does compaction. Or maybe if you Ctrl click delete an entry that'll run compaction?

How about running compaction whenever the dialog / extension window has closed? This would be immediately enough but wouldn’t cause any freezes in the UI.

Sadly only via shortcut, though maybe this would work? https://github.com/jordansissel/xdotool#sending-keys You trigger the shortcut via CLI before password copy, then trigger it again to reopen the clipboard.

Thanks! I’ll try to come up with a way. I’m using Wayland so xdotool is not an option but apparently there is a tool called ydotool that does the same and supports Wayland. I’ll give it a try

SUPERCILEX commented 2 months ago

How about running compaction whenever the dialog / extension window has closed? This would be immediately enough but wouldn’t cause any freezes in the UI.

This is actually a neat idea. As a side note, when I say freeze the UI, I don't just mean that the extension will freeze: this is Gnome and JavaScript so literally the entire shell will freeze, meaning closing the UI and doing a compaction then will stutter the whole shell. That said, I think in 99% of cases it won't be that bad so I'd be open to a PR which runs compaction after the UI is closed if items were deleted.

SUPERCILEX commented 2 months ago

BTW, there's https://github.com/SUPERCILEX/gnome-clipboard-history/pull/170 which I totally forgot and neglected. Need to get back to it.

schlagmichdoch commented 2 months ago

As a side note, when I say freeze the UI, I don't just mean that the extension will freeze: this is Gnome and JavaScript so literally the entire shell will freeze, meaning closing the UI and doing a compaction then will stutter the whole shell.

Isn't there some way to do compaction on a different thread or do Gnome extensions only have access to one thread at a time?

That said, I think in 99% of cases it won't be that bad so I'd be open to a PR which runs compaction after the UI is closed if items were deleted.

I'm currently quite busy but I'll come back to this at the end of sommer I guess. Thanks for being open to changes! :+1:

BTW, there's #170 which I totally forgot and neglected. Need to get back to it.

Sounds promising! KeePassXC is also what I'm using so that'd be great! I'll participate in the conversation over there.

SUPERCILEX commented 2 months ago

Isn't there some way to do compaction on a different thread or do Gnome extensions only have access to one thread at a time?

JavaScript is single threaded so no.

Sounds promising! KeePassXC is also what I'm using so that'd be great! I'll participate in the conversation over there.

Sweet!

schlagmichdoch commented 2 months ago

JavaScript is single threaded so no.

In web development there are service worker for that case. I thought this might exist for gnome too

SUPERCILEX commented 2 months ago

Don't think so unfortunately.

schlagmichdoch commented 2 months ago

I’ve taken a look and apparently it is possible to push processes to another thread by using asynchronous methods:

While you can not run JavaScript on multiple threads, almost all GIO operations have asynchronous variants. These work by collecting the necessary input in the function arguments, sending the work to be done on another thread, then they invoke a callback in the main thread when finished.

https://gjs.guide/guides/gjs/asynchronous-programming.html#asynchronous-operations

There is also a lot of explanation on this page how to prevent freezing of the UI by queuing a process with a low priority.

SUPERCILEX commented 2 months ago

I do use async, but that doesn't fix all the code to prepare reads or writes.

schlagmichdoch commented 2 months ago

I know that you use it extensively, I’m just trying to understand why it blocks the UI then. Do you have an example?

Could this help to make more functions asynchronous? https://gjs.guide/guides/gjs/asynchronous-programming.html#promisify-helper

SUPERCILEX commented 2 months ago

I/O is not the problem, compute is. Without a seperate thread at the OS level, there's no fixing it. Specifically, the extension has to parse the log which involves building up a linked list of entries, building forward and reverse maps, and hashing entry for deduplication. That's not cheap when you start pushing 10s of thousands of entries. This is the meat if you're curious: https://github.com/SUPERCILEX/gnome-clipboard-history/blob/c62c89cee906acd8c4f7d4a0f3c0d64905c5d676/store.js#L114