Skip to content

fix: data races and invalid SVG icon in recorders and menu bar - #18

Open
Chukwuebuka-2003 wants to merge 2 commits into
digimata:masterfrom
Chukwuebuka-2003:fix-data-races
Open

fix: data races and invalid SVG icon in recorders and menu bar#18
Chukwuebuka-2003 wants to merge 2 commits into
digimata:masterfrom
Chukwuebuka-2003:fix-data-races

Conversation

@Chukwuebuka-2003

@Chukwuebuka-2003 Chukwuebuka-2003 commented Jul 29, 2026

Copy link
Copy Markdown

Fixes

1. Data races in MicRecorder and SystemAudioRecorder

Both recorder classes share mutable state (file, firstBufferAt) between the main thread and audio-tap / IOProc callbacks without any synchronization. Reading a stored property from one thread while writing from another is undefined behavior in Swift's memory model.

Wrap the two cross-thread fields in an OSAllocatedUnfairLock-backed LockedState struct. Every read and write on either thread goes through state.withLock { }.

2. Invalid feather SVG icon

The inlined feather SVG used \ at line endings as Swift line continuations, but the double-escape \\ produced a literal backslash before each newline in the runtime string. Inside the <svg> opening tag a bare backslash is not valid XML — neither whitespace nor a valid attribute name character.

NSImage's WebKit-based SVG parser silently recovers in practice, but this is fragile. Removed the superfluous backslash continuations; newlines between attributes are valid XML whitespace.

Files changed

  • Sources/quill/Audio/MicRecorder.swift (+24/-3)
  • Sources/quill/Audio/SystemAudioRecorder.swift (+21/-2)
  • Sources/quill/UI/MenuBarController.swift (+6/-6)

Chukwuebuka-2003 added 2 commits July 29, 2026 22:59
Both recorder classes shared mutable state (file, firstBufferAt)
between the main thread and audio-tap / IOProc callbacks without
synchronization — a Swift undefined behavior under strict concurrency
and a real crash risk under load or on arm64 with compiler reordering.

Replace bare stored properties with OSAllocatedUnfairLock-backed
computed properties. The LockedState struct holds the two fields;
every read/write on either thread goes through state.withLock { }.

Liveness-check fields (livenessFrames, livenessPeak, livenessSettled)
remain plain because they are written only in the tap callback and
read only via DispatchQueue.main.async (fallBackToRaw), which
establishes a happens-before ordering.
Each line of the inlined SVG ended with `\\` (escaped backslash) which
produced a literal `\` before the newline in the runtime string.
Inside the <svg> opening tag this is not valid XML — a bare `\` is
neither whitespace nor a valid attribute name character.

NSImage's WebKit-based SVG parser silently recovers from the error in
practice, but this is fragile. The trailing `\` line continuations
were superfluous anyway (the newlines and indentation are valid XML
whitespace), so removing them yields a correct, parseable SVG.
@Chukwuebuka-2003 Chukwuebuka-2003 changed the title fix: eliminate data races in MicRecorder and SystemAudioRecorder fix: data races and invalid SVG icon in recorders and menu bar Jul 29, 2026
FernandoGomes83 added a commit to FernandoGomes83/quill that referenced this pull request Jul 31, 2026
FernandoGomes83 added a commit to FernandoGomes83/quill that referenced this pull request Jul 31, 2026
…onfigures the input device

Conflict with digimata#18 in MicRecorder: kept digimata#18's OSAllocatedUnfairLock-backed
LockedState and routed digimata#2's code through the computed properties. digimata#2's new
lastBufferAt has the same cross-thread access pattern (written from the tap,
read on main during the restart), so it joins the same locked state rather
than sitting outside it.
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.

1 participant