Skip to content

Issue #1818: Serialize access of a rule-based formatter#1889

Open
itingliu wants to merge 1 commit intoswiftlang:mainfrom
itingliu:bytecountstyle-crash
Open

Issue #1818: Serialize access of a rule-based formatter#1889
itingliu wants to merge 1 commit intoswiftlang:mainfrom
itingliu:bytecountstyle-crash

Conversation

@itingliu
Copy link
Copy Markdown
Contributor

@itingliu itingliu commented Apr 10, 2026

Resolves #1818

ICU rule-based number formatter isn't thread safe. Add a lock to serialize access to this formatter if we happen to use one.

This issue is fixed in upstream ICU, so we will be able to remove this once the fix is available.

ICU rule-based number formatter isn't thread safe. Add a lock to serialize access to this formatter if we happen to use one.

This issue is fixed in [upstream ICU](unicode-org/icu#3928), so we will be able to remove this once the fix is avaiable.
@itingliu itingliu requested a review from a team as a code owner April 10, 2026 00:03
@itingliu
Copy link
Copy Markdown
Contributor Author

@swift-ci please test

@itingliu itingliu changed the title Issue 1818: Serialize access of a rule-based formatter Issue #1818: Serialize access of a rule-based formatter Apr 10, 2026

/// `Sendable` notes: `UNumberFormat` is safe to use from multple threads after initialization and configuration.
// `Sendable` notes: `UNumberFormat` backed by ICU's `DecimalFormat` is safe to use from multiple threads after initialization and configuration. However, `RuleBasedNumberFormat`is not thread-safe. See https://github.com/unicode-org/icu/pull/3928
let uformatter: UnsafeMutablePointer<UNumberFormat?>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Part of me wonders if it's worth wrapping this in a sub type that requires you to access it through withLockIfNeeded like Mutex would. Maybe it's too much ceremony for what it's worth. What do you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Do you mean a

class AlwaysSafeFormatter {
    private let uformatter: UnsafeMutablePointer<UNumberFormat?>
    private let formatLock: Mutex<Void>?
    internal func withLock(...) ... { }
}

And we use AlwaysSafeFormatter.withLock everywhere?

I can see that, but ICULegacyNumberFormatter is already a wrapper. It's also the only (hopefully) place where we optionally lock around an ICU object, so I think for now it's ok to leave it here. But if we ever encounter this pattern again (hopefully not) then I agree we could benefit from this wrapper

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah something like that, just to avoid accidentally forgetting to use the lock. Sounds good yeah I figured it might be a bit more architecture than it's worth if it's all isolated to a small space

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.

0.formatted(.byteCount(style: .binary)) crashes because it's not thread-safe

2 participants