Skip to content

String(format:) intermittently returns an empty string when run concurrently by swift-testing #5152

Closed
@euanh

Description

@euanh

The following test, run from the command line in a loop, will eventually fail at random because the String constructor returns an empty string:

import Foundation
import Testing

@Suite struct FormatTest {
    @Test(arguments: [
        (input: 0o000, expected: "000000"),
        (input: 0o555, expected: "000555"),
        (input: 0o750, expected: "000750"),
        (input: 0o777, expected: "000777"),
        (input: 0o1777, expected: "001777"),
    ])
    func testStringFormat(input: Int, expected: String) async throws {
        #expect(String(format: "%06o", input) == expected)
    }
}

On my machine it fails roughly once in every 20 runs, on different test inputs. The error is always that the constructor returns an empty string. The inputs are fixed and always in a range which can be represented in a 6 character octal string.

􀢄  Test testStringFormat(input:expected:) recorded an issue with 2 arguments input → 1023, expected → "001777" at StringTests.swift:13:9: Expectation failed: (String(format: "%06o", input) →  "") == (expected → "001777")

I only noticed this when I started to use swift-testing, which runs test cases in parallel by default. It has never come up in actual use, as far as I'm aware, because I only use this constructor in single-threaded sequential code.

Could there be a shared buffer somewhere in the CFString underpinnings which makes this constructor not threadsafe? I didn't see anything warning about this in the docs: https://developer.apple.com/documentation/swift/string/init(format:_:).


XCode 16.2 / 16C5032a
macOS 15.1.1 (24B91)

% swift -version
swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions