Skip to content

🐞 Fix crash when searching the action picker in non-English languages - #1193

Open
NicoCorini wants to merge 1 commit into
mrkai77:developfrom
NicoCorini:fix/1187-picker-search-crash
Open

NicoCorini wants to merge 1 commit into
mrkai77:developfrom
NicoCorini:fix/1187-picker-search-crash

Conversation

@NicoCorini

Copy link
Copy Markdown

Description

Typing in the keybind action picker's search field could crash Loop (SIGILL in String.subscript.getter) when the UI language has accented action names. In English every name is ASCII, so it never shows up there.

The subsequence matcher in fuzzyScore moved the pattern's index forward using the action name:

 while tIndex < text.endIndex, pIndex < pattern.endIndex {
     if text[tIndex] == pattern[pIndex] {
-        pIndex = text.index(after: pIndex)
+        pIndex = pattern.index(after: pIndex)
     }
     tIndex = text.index(after: tIndex)
 }

A String.Index remembers the width of the character it points to in the string it came from. For example, with the name "Metà inferiore" and the search "meta", after matching m, e, t the index lands on byte 3, which in the name is the 2-byte "à". Reading the 4-byte search text at that index then goes past its end and traps.

Apart from the one-line fix:

  • fuzzyScore is now static (it uses no view state), so the tests can call it.
  • Added LoopTests/DirectionPickerSearchTests.swift, covering the prefix, substring and subsequence scores plus the regression.

Side effect: some searches containing accented letters that silently returned no results now match correctly (e.g. "mà ie" → "Metà inferiore"). Scores for ASCII names are unchanged.

Fixes #1187

How has this been tested?

macOS Sequoia 15.8.1, Intel MacBook Pro.

  • DirectionPickerSearchTests: before the fix, fuzzyScore("Metà inferiore", "meta") crashes the test host with the same stack as the issue (String.subscript.getter ← fuzzyScore). After the fix all 6 tests pass.
  • Ran the old and fixed fuzzyScore against every localized action name from Localizable.xcstrings with random search strings: the old code crashes for it, de, fr, es, pt-BR and pl; the fixed code never crashes.
  • Manually in the app with the UI in Italian (-AppleLanguages (it)): typed and deleted many strings, including "meta" and accented ones, in Keybinds → Add → action picker. No crash.

Two things I noticed while testing, not touched in this PR:

  • On develop, LoopTests doesn't build because CycleProgressStoreTests.swift uses API that no longer exists on CycleProgressStore. I temporarily moved that file out locally to run the tests.
  • The test host is Loop itself, so starting tests closes any running Loop instance (the terminate broadcast in AppDelegate).

Checklist:

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation if applicable
  • I have no unrelated changes in this PR.

Please describe to which degree, if any, an LLM was used in creating this pull request.

I used Claude (Claude Code) to read the crash reports and the source, write a small harness that reproduced the crash outside the app, and draft the fix, the tests and this description. A separate Claude instance reviewed the diff. I reproduced the original crash myself, verified the fix manually in the app, and reviewed and edited all code and text.

DirectionPickerView.fuzzyScore advanced the pattern's index with
text.index(after:). A String.Index remembers how wide the character at
that position is in the string it came from, so when an action name has
a multi-byte character (e.g. "à" in the Italian "Metà inferiore"), the
next lookup in the search text read past its end and trapped.

Advance the index with pattern.index(after:) instead. fuzzyScore is now
static so it can be unit tested, and DirectionPickerSearchTests covers
the regression.

Fixes mrkai77#1187
@SenpaiHunters

Copy link
Copy Markdown
Collaborator

I'm unable to recreate this crash. Could you attach a screen recording of the version you're testing with (so, about > version) and any typed queries that cause the crash?

@NicoCorini

Copy link
Copy Markdown
Author

I'm unable to recreate this crash. Could you attach a screen recording of the version you're testing with (so, about > version) and any typed queries that cause the crash?

Sure, recording attached: Loop 🧪 1.4.3 (1783), macOS 15.8.1, system language Italian. The About window at the start shows the version, and the macOS crash dialog at the end shows EXC_BAD_INSTRUCTION (SIGILL). The crashed thread's stack is String.subscript.getter ← DirectionPickerView.computeSearchResults().

The key detail is the language: the crash only happens when action names contain non-ASCII characters, so it won't reproduce in English. To reproduce:

  1. Run Loop in Italian (e.g. defaults write com.MrKai77.Loop AppleLanguages '("it")', then relaunch)
  2. Settings → Keybinds → open the action picker on a keybind
  3. Type meta → crash on the last letter ("Metà …" has a multi-byte à)

It also crashes with German, French, Spanish, Portuguese (BR) and Polish action names. Without the fix, the regression test subsequenceMatchAgainstNonASCIINameDoesNotCrash in this PR crashes the test host on develop.

loop-1187-crash.mp4

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐞 Crash when editing the search field in the keybind action picker

2 participants