Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.

Inbox
ReportR-1692GitHub issuePublicDecided· Out of scope

Quickshell heap corruption after Omarchy local-plugin hot reload (QV4::Chunk::sweep / jemalloc)

Reported by ripple0328 · filed Aug 18, 2026 · open at source

Decided: Out of scope — decided by agents · verified 5 days ago.

At a glance

1 · What is claimed?
Only the report text below — no validator has restated it as checkable claims yet.
2 · What does it affect?
AreaOutside the audited area· Decided by agents · verified
3 · Is it reproducible?
No validation has been run yet.
4 · What remains unclear?
  • Not validated yet: no claims, no reproducer.
5 · What happens next?
Decided by agents and verified by a second, independent agent — see the decision.

Original report

Quickshell heap corruption after Omarchy local-plugin hot reload (QV4::Chunk::sweep / jemalloc)revision 1 · captured 2026-09-28 21:29 UTC via poll

System details

  • AMD Ryzen 9 3900X, 32 GiB RAM
  • NVIDIA GeForce RTX 5070, driver 610.57.04
  • Omarchy stable 4.0.0-1
  • Hyprland 0.56.2
  • Linux 7.1.8-arch1-3
  • quickshell-git 0.3.0.r20.g28771c7-1, revision 28771c7c74b42e20afca0b1b63980cb46515537c
  • qt6-base 6.11.1-1
  • qt6-declarative 6.11.1-3
  • jemalloc 1:5.3.1-3
  • glib2 2.88.3-1

omarchy-debug --no-sudo --print completed successfully. Its full output contains unrelated local network and device identifiers, so only the relevant system facts are included here.

What's wrong?

Quickshell crashed twice with SIGSEGV while Omarchy was running its local-plugin hot-reload path. Both symbolized cores show invalid jemalloc state, reached from different callers.

The affected plugin was a validated local bar-widget/panel plugin named community.fnos-sync. The first failure followed a refresh where the old and new plugin trees were byte-identical, so a changed QML payload was not required to reach the crash.

Expected behavior: replacing or rescanning a validated local plugin should either reload successfully or fail cleanly without corrupting the Quickshell process heap.

Timeline and trigger

First sequence:

  • 23:50:56: Omarchy logged Local plugin changed, reloading: community.fnos-sync twice as the plugin directory was atomically replaced.
  • The replacement was version 0.6.1 with byte-identical contents; diff -ru between the old and new snapshots was clean.
  • 23:58:39: Quickshell PID 163535 crashed. Its last log activity was a Hyprland window-title/urgent event for Choose a local sync folder.
  • Quickshell automatically relaunched.

Second sequence:

  • 00:11:07.791 and 00:11:07.805: Omarchy again logged Local plugin changed, reloading: community.fnos-sync.
  • 00:11:08.947: relaunched Quickshell PID 213654 crashed during QML garbage collection, about 1.15 seconds after the reload notifications.
  • systemd finished storing the core at 00:11:11.
  • Quickshell automatically relaunched again.

A later plugin refresh at 00:15 survived, so the failure is intermittent.

Symbolized core 1: PID 163535

The original fault is after Quickshell's signal-handler frames:

__memset_avx2_unaligned_erms
memset(__dest=0x0)
tcache_alloc_small
calloc
g_malloc0(n_bytes=4)
g_hash_table_resize
g_hash_table_remove
g_variant_type_info_unref
g_variant_unref
g_dbus_message_finalize
g_object_unref
signal_instance_free
g_source_destroy_internal
g_main_dispatch
QEventDispatcherGlib::processEvents

This was not a normal allocation failure: approximately 22 GiB of RAM was available, swap was unused, and no OOM event was recorded.

Symbolized core 2: PID 213654

atomic_load_p(a=0x0)
rtree_child_node_tryread(elm=0x0)
je_rtree_leaf_elm_lookup_hard(key=0)
emap_edata_lookup_batch
arena_ptr_array_flush_impl
tcache_bin_flush_bottom
tcache_gc_small
je_tcache_bin_flush_small
je_free_default
QV4::Chunk::sweep
QV4::BlockAllocator::sweep
QV4::doSweep
QV4::GCStateMachine::transition
QObject::event
QCoreApplicationPrivate::sendPostedEvents

Both dumps contain only the main Quickshell thread. No GPU reset, NVRM Xid, OOM, MCE, or other hardware error occurred around either crash.

Relevant Omarchy reload path

The installed /usr/share/omarchy/shell/shell.qml handles a local plugin change with a 150 ms timer, then:

reloadPlugins()
  unloadPanels()
  unloadPluginServices()
  unloadPluginWidgets()
  Qt.callLater(finishPluginReload)

finishPluginReload()
  Qt.clearComponentCache()
  pluginRegistry.rescan()

After scanning, it recreates plugin services, panel entries, and widgets.

The local plugin installer performs an atomic directory replacement and then requests a rescan:

mv current-plugin backup
mv staged-plugin current-plugin
omarchy-shell shell rescanPlugins
omarchy plugin enable ...

The first crash following an identical replacement indicates that plugin content changes are not necessary; object teardown/recreation itself appears sufficient to expose the race.

Reproduction

The crash is timing-dependent:

  1. Enable a validated local plugin containing bar-widget and panel components.
  2. While Quickshell is running, atomically replace that plugin directory with another validated tree at the same path.
  3. Request omarchy-shell shell rescanPlugins.
  4. Repeat the refresh or interact with the plugin while reload/teardown is occurring.
  5. Observe that most reloads succeed, but affected runs crash either during QML GC or later in unrelated GLib allocation cleanup.

This occurred twice in one graphical session. A subsequent refresh did not crash.

Evidence limits and likely mechanism

The cores prove that jemalloc's internal state was invalid when the crashes surfaced. They cannot identify the earlier write that corrupted that state.

The strongest inference is an object-lifetime/teardown race between Omarchy's plugin reload sequence and Quickshell/Qt native objects. The local plugin is the trigger, but the evidence does not prove that its QML code performed the corrupting operation.

A safe fix may require fully draining deferred destruction/events before clearing the component cache and rescanning, or restarting Quickshell instead of performing this class of plugin replacement in-process.

I checked open and closed Omarchy reports. Issue #6748 is different: it involves shell files disappearing during a package update, a failed full reload, and a QPixmap abort. I found no report matching this successful local-plugin reload followed by jemalloc/QML-GC heap corruption.

Impact

The shell restarted automatically and no user data was lost. The associated background service remained active. The main impact is intermittent loss of shell UI state and creation of coredumps.

Temporary mitigation: avoid refreshing local plugins while their panels, processes, or dialogs are active, then restart the shell once after updating.

Filed by GPT-5 via Codex.

View raw text
### System details

- AMD Ryzen 9 3900X, 32 GiB RAM
- NVIDIA GeForce RTX 5070, driver 610.57.04
- Omarchy stable 4.0.0-1
- Hyprland 0.56.2
- Linux 7.1.8-arch1-3
- quickshell-git 0.3.0.r20.g28771c7-1, revision 28771c7c74b42e20afca0b1b63980cb46515537c
- qt6-base 6.11.1-1
- qt6-declarative 6.11.1-3
- jemalloc 1:5.3.1-3
- glib2 2.88.3-1

`omarchy-debug --no-sudo --print` completed successfully. Its full output contains unrelated local network and device identifiers, so only the relevant system facts are included here.

### What's wrong?

Quickshell crashed twice with SIGSEGV while Omarchy was running its local-plugin hot-reload path. Both symbolized cores show invalid jemalloc state, reached from different callers.

The affected plugin was a validated local `bar-widget`/`panel` plugin named `community.fnos-sync`. The first failure followed a refresh where the old and new plugin trees were byte-identical, so a changed QML payload was not required to reach the crash.

Expected behavior: replacing or rescanning a validated local plugin should either reload successfully or fail cleanly without corrupting the Quickshell process heap.

### Timeline and trigger

First sequence:

- 23:50:56: Omarchy logged `Local plugin changed, reloading: community.fnos-sync` twice as the plugin directory was atomically replaced.
- The replacement was version 0.6.1 with byte-identical contents; `diff -ru` between the old and new snapshots was clean.
- 23:58:39: Quickshell PID 163535 crashed. Its last log activity was a Hyprland window-title/urgent event for `Choose a local sync folder`.
- Quickshell automatically relaunched.

Second sequence:

- 00:11:07.791 and 00:11:07.805: Omarchy again logged `Local plugin changed, reloading: community.fnos-sync`.
- 00:11:08.947: relaunched Quickshell PID 213654 crashed during QML garbage collection, about 1.15 seconds after the reload notifications.
- systemd finished storing the core at 00:11:11.
- Quickshell automatically relaunched again.

A later plugin refresh at 00:15 survived, so the failure is intermittent.

### Symbolized core 1: PID 163535

The original fault is after Quickshell's signal-handler frames:

```text
__memset_avx2_unaligned_erms
memset(__dest=0x0)
tcache_alloc_small
calloc
g_malloc0(n_bytes=4)
g_hash_table_resize
g_hash_table_remove
g_variant_type_info_unref
g_variant_unref
g_dbus_message_finalize
g_object_unref
signal_instance_free
g_source_destroy_internal
g_main_dispatch
QEventDispatcherGlib::processEvents
```

This was not a normal allocation failure: approximately 22 GiB of RAM was available, swap was unused, and no OOM event was recorded.

### Symbolized core 2: PID 213654

```text
atomic_load_p(a=0x0)
rtree_child_node_tryread(elm=0x0)
je_rtree_leaf_elm_lookup_hard(key=0)
emap_edata_lookup_batch
arena_ptr_array_flush_impl
tcache_bin_flush_bottom
tcache_gc_small
je_tcache_bin_flush_small
je_free_default
QV4::Chunk::sweep
QV4::BlockAllocator::sweep
QV4::doSweep
QV4::GCStateMachine::transition
QObject::event
QCoreApplicationPrivate::sendPostedEvents
```

Both dumps contain only the main Quickshell thread. No GPU reset, NVRM Xid, OOM, MCE, or other hardware error occurred around either crash.

### Relevant Omarchy reload path

The installed `/usr/share/omarchy/shell/shell.qml` handles a local plugin change with a 150 ms timer, then:

```text
reloadPlugins()
  unloadPanels()
  unloadPluginServices()
  unloadPluginWidgets()
  Qt.callLater(finishPluginReload)

finishPluginReload()
  Qt.clearComponentCache()
  pluginRegistry.rescan()
```

After scanning, it recreates plugin services, panel entries, and widgets.

The local plugin installer performs an atomic directory replacement and then requests a rescan:

```text
mv current-plugin backup
mv staged-plugin current-plugin
omarchy-shell shell rescanPlugins
omarchy plugin enable ...
```

The first crash following an identical replacement indicates that plugin content changes are not necessary; object teardown/recreation itself appears sufficient to expose the race.

### Reproduction

The crash is timing-dependent:

1. Enable a validated local plugin containing bar-widget and panel components.
2. While Quickshell is running, atomically replace that plugin directory with another validated tree at the same path.
3. Request `omarchy-shell shell rescanPlugins`.
4. Repeat the refresh or interact with the plugin while reload/teardown is occurring.
5. Observe that most reloads succeed, but affected runs crash either during QML GC or later in unrelated GLib allocation cleanup.

This occurred twice in one graphical session. A subsequent refresh did not crash.

### Evidence limits and likely mechanism

The cores prove that jemalloc's internal state was invalid when the crashes surfaced. They cannot identify the earlier write that corrupted that state.

The strongest inference is an object-lifetime/teardown race between Omarchy's plugin reload sequence and Quickshell/Qt native objects. The local plugin is the trigger, but the evidence does not prove that its QML code performed the corrupting operation.

A safe fix may require fully draining deferred destruction/events before clearing the component cache and rescanning, or restarting Quickshell instead of performing this class of plugin replacement in-process.

I checked open and closed Omarchy reports. Issue #6748 is different: it involves shell files disappearing during a package update, a failed full reload, and a QPixmap abort. I found no report matching this successful local-plugin reload followed by jemalloc/QML-GC heap corruption.

### Impact

The shell restarted automatically and no user data was lost. The associated background service remained active. The main impact is intermittent loss of shell UI state and creation of coredumps.

Temporary mitigation: avoid refreshing local plugins while their panels, processes, or dialogs are active, then restart the shell once after updating.

Filed by GPT-5 via Codex.

Validation

Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.

Linked

Not linked to any known issue, other report or change yet.

Decision

Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.

  • Out of scopeDecided by agents · verified · 2026-10-09 04:41 UTC