Skip to content

test: use Task.sleep(nanoseconds:) so SwiftLMTests runs in Release on Swift 6.2 - #256

Merged
solderzzc merged 1 commit into
mainfrom
sl71/clientdisconnect-release
Nov 3, 2026
Merged

solderzzc merged 1 commit into
mainfrom
sl71/clientdisconnect-release

Conversation

@solderzzc

Copy link
Copy Markdown
Member

Problem

mlx-swift-lm runs the SwiftLM tests in Release on Xcode 26.3 (Swift 6.2.4). There, ClientDisconnectTests aborts the whole XCTest process:

freed pointer was not the last allocation   (signal 6)

This hid every test after it. The suite passes in Debug and on Swift 6.4.

What I found (reproduced locally with /Volumes/Work/Xcode-26.3.app, Swift 6.2.4)

  • The crash report's trapping stack is swift_task_dealloc called from the specialized Task<>.sleep<A>(for:tolerance:clock:) compiled into the test bundle. It is not in Server.swift's cancellation code.
  • A test that contains only try? await Task.sleep(for: .milliseconds(10)) crashes. It does not need cancellation, a Task, DeferredCancellation, NIO, or an import SwiftLM. ContinuousClock().sleep(for:) crashes too.
  • Task.sleep(nanoseconds:) does not crash. An empty async test and a trivial Task { 1 } do not crash.
  • Not reproduced in a standalone swiftc -O program, nor in a minimal package with one XCTest (tools 5.9 or 6.0, executable target with @main, -enable-testing, Release) on 6.2.4. So I could not reduce it to an upstream bug report. The exact compiler trigger is unknown.

Change

Replace the five Task.sleep(for: ...) calls in ClientDisconnectTests and DFlashStreamBridgeTests with Task.sleep(nanoseconds:) and the same durations. No production code changes.

Verification (Swift 6.2.4, swift test -c release --no-parallel --skip-build --disable-swift-testing, mlx.metallib copied next to the test bundle)

  • ClientDisconnectTests: 7 tests, 0 failures, EXIT=0 (before: signal 6).
  • DFlashStreamBridgeTests: 4 tests, 0 failures, EXIT=0.
  • Whole SwiftLMTests bundle: 464 tests, 10 skipped, 0 failures, EXIT=0.

Not verified

  • Server.swift has seven Task.sleep(for:) calls in production code. The same toolchain's Release build runs them in mlx-swift-lm's speculative-decoding script, which passed, but I have not shown they are unaffected. I did not change them.
  • Debug and Swift 6.4 behaviour is unchanged by construction; this PR's CI covers Debug.

🤖 Generated with Claude Code

…ift 6.2

On Swift 6.2.4 (Xcode 26.3) in a Release build, any Task.sleep(for:) call in the
SwiftLMTests bundle aborts the XCTest process with "freed pointer was not the last
allocation" (swift_task_dealloc, called from the specialized
Task<>.sleep<A>(for:tolerance:clock:)). It needs neither cancellation nor any
SwiftLM code: a test containing only `try? await Task.sleep(for: .milliseconds(10))`
crashes, while the nanoseconds overload does not. Swift 6.4 is not affected.

Switch the test sleeps to Task.sleep(nanoseconds:) with the same durations.
ClientDisconnectTests (7) and the whole SwiftLMTests bundle (464) pass in Release
on Swift 6.2.4.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
@solderzzc
solderzzc merged commit 69bc71c into main Nov 3, 2026
15 checks passed
@solderzzc
solderzzc deleted the sl71/clientdisconnect-release branch November 4, 2026 03:30
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