Skip to content

Fix crash on Linux when testing the archive plugin#641

Merged
sebsto merged 2 commits intomainfrom
sebsto/fix_plugin
Feb 16, 2026
Merged

Fix crash on Linux when testing the archive plugin#641
sebsto merged 2 commits intomainfrom
sebsto/fix_plugin

Conversation

@sebsto
Copy link
Collaborator

@sebsto sebsto commented Feb 12, 2026

Fix a rare crash in CI on the archive plugin.

The crash is a race condition in PluginUtils.swift's execute method. The code set a terminationHandler on the Process that called readToEnd() on the pipe, while simultaneously the readabilityHandler could still be firing on the same pipe's file handle. On Linux (x86_64, Ubuntu 24.04 in CI), this race corrupts memory during Swift runtime metadata resolution (swift_conformsToProtocol, _swift_getGenericMetadata), which manifests as the SIGSEGV we're seeing in _dispatch_event_loop_drain.

The fix:

I removed the terminationHandler entirely. Since waitUntilExit() is already called synchronously, we know the process is done.
After waitUntilExit(), we set readabilityHandler = nil to stop the async reads, then do one final readToEnd() on the output queue to drain any remaining data.
This eliminates the race between the readability handler and the termination handler competing over the same file handle.

@sebsto sebsto self-assigned this Feb 12, 2026
@sebsto sebsto added the 🔨 semver/patch No public API change. label Feb 12, 2026
@sebsto sebsto requested review from 0xTim and Copilot February 14, 2026 11:14
@sebsto
Copy link
Collaborator Author

sebsto commented Feb 14, 2026

@0xTim When time permits, can you check this change on the plugin ? It fixes a race condition that causes the plugin to crash from time to time.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a CI-only crash on Linux in the AWSLambdaPackager archive plugin by removing Process.terminationHandler output draining and instead stopping readabilityHandler after waitUntilExit(), then draining remaining pipe output.

Changes:

  • Removed Process.terminationHandler that performed a readToEnd() on the output pipe.
  • After waitUntilExit(), disabled readabilityHandler and scheduled a final readToEnd() to drain remaining output.
  • Updated comments to document the Linux race/SIGSEGV rationale.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +104 to 108
// Read any remaining data from the pipe
outputQueue.async { outputHandler(try? pipe.fileHandleForReading.readToEnd()) }

// wait for output to be fully processed
outputSync.wait()
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

outputSync.wait() is not guaranteed to wait for the final outputQueue.async (or any pending readability-handler enqueues), because outputSync.enter() happens inside outputHandler after the async work has started. If wait() runs before the async block executes, the group count is still 0 and wait() can return early, causing truncated output and potential mutation of outputMutex after output is read. Move the DispatchGroup enter/leave to wrap each outputQueue.async submission (or drain the queue with outputQueue.sync {} / use outputQueue.sync for the final readToEnd).

Copilot uses AI. Check for mistakes.
@sebsto sebsto merged commit 4a917a7 into main Feb 16, 2026
26 of 50 checks passed
@sebsto sebsto deleted the sebsto/fix_plugin branch February 16, 2026 11:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔨 semver/patch No public API change.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments