Skip to content

Fix timeout races and other issues from the v2 review - #198

Merged
drowaudio merged 3 commits into
v2from
dev/review-branch-309a17
Oct 14, 2026
Merged

drowaudio merged 3 commits into
v2from
dev/review-branch-309a17

Conversation

@drowaudio

Copy link
Copy Markdown
Contributor

Fixes from a pre-merge review of v2 against master.

Races between timeouts and report/log writing

  • validate: a mutex protects the log stream, so the timeout thread can't free it while a test is writing to it. The timeout thread is stopped once the tests finish, so it can't write its "timed out" report over the real one.
  • test: the worker and the watchdog each claim the report with an atomic flag, and only the first to claim it writes. The placeholder report is written before the watchdog starts.

Other fixes

  • Crash log: moved back to the per-user temp directory. The path is computed up front for the signal handler, and the file is opened with O_NOFOLLOW. The handler no longer passes null names to %s.
  • Message-thread helpers share one callOnMessageThreadAndWait(), which rethrows on the calling thread, so a throw can't leave the caller waiting forever. Acceptance plugin teardown can no longer throw out of a destructor.
  • Child-process output no longer garbles UTF-8 characters split across reads (ChildProcessOutputDecoder).
  • operator delete no longer throws (it's noexcept, so a throw ended the process). operator new throws std::bad_alloc instead of returning null.
  • pluginval test:
    • accepts --name=value options, as validate does;
    • rejects a value on --record-missing.
  • --output-filename without --output-dir is resolved against the working directory.
  • GitHub Actions scripts delete each report before running, so a stale one is never read.
  • VST3 validator extraction deletes the binary if writing it or chmod fails.
  • TestConfig reuses settings_parser::resolvePluginPath.
  • Typos, spacing, namespace comments and docs.

Testing

  • Debug build on macOS.
  • pluginval run-tests passes, with new tests for --name=value and the UTF-8 decoder.
  • The acceptance CTests pass, repeated 6 times.
  • With --timeout-ms set to 1 to 200, the report always agreed with the exit code.
  • The callOnMessageThreadAndWait() refactor touches every VST3 call made on the message thread, so CI on Linux and Windows matters here.

- validate: guard the log stream with a mutex so the timeout thread can't
  reset it while a test is writing to it, and stop the timeout thread once
  the tests finish so it can't write its report over the real one.
- test: the worker and the watchdog now claim the report with an atomic
  flag and only the first to claim it writes. The placeholder report is
  written before the watchdog starts.
- Crash log: back in the per-user temp directory (path computed up front for
  the signal handler) instead of a shared /tmp file, opened with O_NOFOLLOW.
- Crash handler: don't pass null image/symbol names to %s; cast the offset
  for %ld; include <string.h> and <algorithm>.
- --output-filename without --output-dir is resolved against the working
  directory rather than building a juce::File from a relative path.
- pluginval test accepts --name=value options, as validate does.
- GitHub Actions: delete each report before running so a stale one from an
  earlier run is never read.
- TestConfig::getPluginPathOrID uses settings_parser::resolvePluginPath.
- vst3validator: delete the extracted binary if writing or chmod fails.
- Typos, spacing, closing-namespace comments, an em dash, and the JUCE
  version in CLAUDE.md.
- pluginval test: --record-missing=<value> is an error rather than the value
  being taken as the config path.
- Message-thread helpers share one callOnMessageThreadAndWait() that rethrows
  an exception on the calling thread, so a throw can't leave the caller
  waiting forever. Used by the VST3 helpers, the editor helpers, the plugin
  scan, message-thread tests and the acceptance plugin teardown, which now
  can't throw out of its destructor.
- Child process output is decoded with ChildProcessOutputDecoder, so a UTF-8
  character split across two reads is no longer garbled.
- operator delete no longer throws (it's noexcept, so that terminated the
  process); operator new throws std::bad_alloc rather than returning null.
  Removed the unused violationError().
- Replaced the em/en dashes in CLAUDE.md and the acceptance design doc.
@drowaudio
drowaudio merged commit 72fe1cd into v2 Oct 14, 2026
13 checks passed
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