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-474GitHub issuePublicFixed

omarchy-menu-keybindings: mock 'noop' table causes unbounded infinite loop and 100% CPU when config iterates with ipairs

Reported by LoupiBe · filed Sep 16, 2026 · open at source

Decided: Duplicate — decided by agents · verified 3 days ago.

R-1816 is the earliest report of this defect — filed Aug 15, 2026, open upstream. This report (filed Sep 16, 2026) describes the same defect, so it is folded under it in the inbox.

Decided by agents · verified· Oct 8, 2026

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?
AreaIn the audited areamenu· 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

omarchy-menu-keybindings: mock 'noop' table causes unbounded infinite loop and 100% CPU when config iterates with ipairsrevision 1 · captured 2026-09-28 21:23 UTC via poll

System details

Intel Core i7-8665U, Intel UHD Graphics 620, Omarchy 4.0.4-1

What's wrong?

Description

When pressing SUPER + K (or running omarchy menu keybindings / omarchy-menu-keybindings), if the user's Hyprland Lua configuration (or any module it requires) uses ipairs() on a function call or table that falls back to the mock noop object (for example, ipairs(hl.get_windows() or {})), the subshell Lua process enters an infinite loop, never exits, and spins at 100% CPU.

Each time SUPER + K is pressed, another un-reaped lua process is spawned and pegs a CPU core permanently.

Steps to Reproduce

  1. In ~/.config/hypr/hyprland.lua (or a required module), add any standard Lua loop that iterates over a mockable Hyprland API, such as:
   for _, w in ipairs(hl.get_windows() or {}) do
     -- window handling logic
   end

(Note: This is completely valid Lua inside the real Hyprland compositor).
2. Clear the keybindings cache:

   rm -f ~/.cache/omarchy/keybindings-*.records
  1. Press SUPER + K or execute:
   omarchy-menu-keybindings --print
  1. Observe that the command never completes, and ps aux | grep lua shows a lua process consuming 100% CPU.

Root Cause

In /usr/share/omarchy/bin/omarchy-menu-keybindings:

local noop
noop = setmetatable({}, {
  __index = function()
    return noop
  end,
  __call = function()
    return noop
  end,
})

hl = setmetatable({
  dsp = dsp_proxy("hl.dsp"),
  bind = function(keys, bind_dispatcher, opts)
    -- ...
  end,
  get_config = function()
    return nil
  end,
}, {
  __index = function()
    return noop
  end,
})

omarchy-menu-keybindings parses user keybindings by executing dofile("~/.config/hypr/hyprland.lua") in a standalone lua subshell.
To avoid crashes on unhandled Hyprland APIs, it falls back to a recursive noop mock.

However, in Lua, ipairs(t) iterates sequentially (t[1], t[2], t[3], ...) until the table returns nil. Because noop's __index returns noop (which is truthy) for all keys, noop[1], noop[2], etc. are never nil. As a result, ipairs(noop) becomes an infinite loop.

Proposed Solution

In /usr/share/omarchy/bin/omarchy-menu-keybindings, update noop so that numeric index lookups return nil:

local noop
noop = setmetatable({}, {
  __index = function(self, key)
    if type(key) == "number" then
      return nil
    end
    return noop
  end,
  __call = function()
    return noop
  end,
  __len = function()
    return 0
  end,
})

Additionally, common query functions like hl.get_windows, hl.get_monitors, hl.get_workspaces can be explicitly stubbed on hl to return {}:

  get_windows = function() return {} end,
  get_monitors = function() return {} end,
  get_workspaces = function() return {} end,
View raw text
### System details
Intel Core i7-8665U, Intel UHD Graphics 620, Omarchy 4.0.4-1

### What's wrong?

#### Description
When pressing `SUPER + K` (or running `omarchy menu keybindings` / `omarchy-menu-keybindings`), if the user's Hyprland Lua configuration (or any module it `require`s) uses `ipairs()` on a function call or table that falls back to the mock `noop` object (for example, `ipairs(hl.get_windows() or {})`), the subshell Lua process enters an infinite loop, never exits, and spins at 100% CPU.

Each time `SUPER + K` is pressed, another un-reaped `lua` process is spawned and pegs a CPU core permanently.

#### Steps to Reproduce
1. In `~/.config/hypr/hyprland.lua` (or a required module), add any standard Lua loop that iterates over a mockable Hyprland API, such as:
   ```lua
   for _, w in ipairs(hl.get_windows() or {}) do
     -- window handling logic
   end
   ```
   *(Note: This is completely valid Lua inside the real Hyprland compositor).*
2. Clear the keybindings cache:
   ```bash
   rm -f ~/.cache/omarchy/keybindings-*.records
   ```
3. Press `SUPER + K` or execute:
   ```bash
   omarchy-menu-keybindings --print
   ```
4. Observe that the command never completes, and `ps aux | grep lua` shows a `lua` process consuming 100% CPU.

#### Root Cause
In `/usr/share/omarchy/bin/omarchy-menu-keybindings`:
```lua
local noop
noop = setmetatable({}, {
  __index = function()
    return noop
  end,
  __call = function()
    return noop
  end,
})

hl = setmetatable({
  dsp = dsp_proxy("hl.dsp"),
  bind = function(keys, bind_dispatcher, opts)
    -- ...
  end,
  get_config = function()
    return nil
  end,
}, {
  __index = function()
    return noop
  end,
})
```

`omarchy-menu-keybindings` parses user keybindings by executing `dofile("~/.config/hypr/hyprland.lua")` in a standalone `lua` subshell.
To avoid crashes on unhandled Hyprland APIs, it falls back to a recursive `noop` mock.

However, in Lua, `ipairs(t)` iterates sequentially (`t[1]`, `t[2]`, `t[3]`, ...) until the table returns `nil`. Because `noop`'s `__index` returns `noop` (which is truthy) for **all** keys, `noop[1]`, `noop[2]`, etc. are never `nil`. As a result, `ipairs(noop)` becomes an infinite loop.

#### Proposed Solution
In `/usr/share/omarchy/bin/omarchy-menu-keybindings`, update `noop` so that numeric index lookups return `nil`:
```lua
local noop
noop = setmetatable({}, {
  __index = function(self, key)
    if type(key) == "number" then
      return nil
    end
    return noop
  end,
  __call = function()
    return noop
  end,
  __len = function()
    return 0
  end,
})
```
Additionally, common query functions like `hl.get_windows`, `hl.get_monitors`, `hl.get_workspaces` can be explicitly stubbed on `hl` to return `{}`:
```lua
  get_windows = function() return {} end,
  get_monitors = function() return {} end,
  get_workspaces = function() return {} end,
```

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

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.

  • DuplicateR-1816Decided by agents · verified · 2026-10-08 22:03 UTC