Sitelet https://github.com/flutter/flutter/pull/190488
Skip to content

iOS,macOS: make Logger thread-safe, conform to Sendable - #190488

Merged
cbracken merged 1 commit into
flutter:masterfrom
cbracken:logger-threadsafe
Aug 4, 2026
Merged

cbracken merged 1 commit into
flutter:masterfrom
cbracken:logger-threadsafe

Conversation

@cbracken

@cbracken cbracken commented Aug 4, 2026 •

Copy link
Copy Markdown
Member

Previously, Logger.shared was a mutable static variable, and updating Logger.logLevel or Logger.outputWriter replaced the entire singleton instance without any synchronisation. This could cause data races when logging from multiple threads, and prevented Logger from conforming to Sendable under strict Swift concurrency.

We now make shared an immutable constant and guard its mutable logLevel and outputWriter state behind a lock.

The caller-supplied message autoclosure is evaluated outside the lock, both to keep the lock scope minimal and to avoid deadlocking should the closure re-enter Logger since the lock is not reentrant.

Issue: #44030
Issue: #181683

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

@cbracken
cbracken requested a review from a team as a code owner August 4, 2026 00:07
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Aug 4, 2026
@github-actions github-actions Bot added platform-ios iOS applications specifically engine flutter/engine related. See also e: labels. a: desktop Running on desktop team-ios Owned by iOS platform team team-macos Owned by the macOS platform team labels Aug 4, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request introduces thread safety to the Darwin platform Logger by conforming LogLevel, Logger, and OutputWriter types to Sendable (or @unchecked Sendable) and protecting shared state with an NSLock. It also adds a concurrent test to verify behavior under TSan. Feedback on the changes highlights compatibility issues with older iOS and macOS deployment targets due to the use of lock.withLock (which requires iOS 16.0+ / macOS 13.0+), recommending manual lock() and unlock() calls instead. Additionally, the review points out a potential data race in StringOutputWriter where mutable properties are accessed concurrently in tests without synchronization.

@cbracken
cbracken force-pushed the logger-threadsafe branch 2 times, most recently from 118a193 to 16c52a0 Compare August 4, 2026 02:53
Previously, `Logger.shared` was a mutable static variable, and updating
`Logger.logLevel` or `Logger.outputWriter` replaced the entire singleton
instance without any synchronisation. This could cause data races when
logging from multiple threads, and prevented `Logger` from conforming to
`Sendable` under strict Swift concurrency.

We now make `shared` an immutable constant and guard its mutable
`logLevel` and `outputWriter` state behind a lock.

The caller-supplied message autoclosure is evaluated outside the lock,
both to keep the lock scope minimal and to avoid deadlocking should the
closure re-enter `Logger` since the lock is not reentrant.

Issue: flutter#44030
@cbracken
cbracken force-pushed the logger-threadsafe branch from 16c52a0 to 9bb1ba1 Compare August 4, 2026 06:56
// someone accidentally calling the Logger from within the autoclosure.
let line = message()
lock.withLock {
_outputWriter.writeLine(level: level, line)

@LongCatIsLooong LongCatIsLooong Aug 4, 2026 •

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.

It looks like writeLine calls are always protected by a NSLock in Logger, but the OutputWriter.writeLine implementation typically still have be thread-safe because it can be used outside of Logger.

I feel it makes a little bit more sense to make it OutputWriter's responsibility to make sure its writeLine implementation is thread-safe (which is already the case since OutputWriter must be Sendable and writeLine is nonisolated), instead of trying to guarantee thread-safety on both ends, so:

lock.withLock { _outputWriter }.writeLine(level: level, message())

A potential issue with the current implementation is that in case the output writer does something weird in writeLine (like accessing the Logger) it looks possible to cause a deadlock since the lock is not recursive.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

In our case OutputWriter is our own internal protocol and both implementations are at the bottom of this file and don't use locks so we're safe. I've got a followup that replaces this altogether with os_log which will solve it altogether though!

@cbracken
cbracken added this pull request to the merge queue Aug 4, 2026
Merged via the queue into flutter:master with commit 2d5d4c2 Aug 4, 2026
16 of 17 checks passed
@cbracken
cbracken deleted the logger-threadsafe branch August 4, 2026 22:31
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Aug 10, 2026
…12420)

Manual roll requested by stuartmorgan@google.com

flutter/flutter@b766512...27b0988

2026-08-05 kevmoo@users.noreply.github.com reland(tool): remove redundant --enable-experiment=record-use flag (flutter/flutter#190591)
2026-08-05 chris@bracken.jp Windows: Propagate enabled accessibility state (flutter/flutter#190507)
2026-08-05 engine-flutter-autoroll@skia.org Roll Fuchsia Test Scripts from ltbuIH9Z3T_yOuigu... to vcANVO8VIDQHasH1X... (flutter/flutter#190589)
2026-08-05 256906086+mvincentong@users.noreply.github.com Document frozen embedder API structs (flutter/flutter#186842)
2026-08-05 49402500+fahaddoc@users.noreply.github.com Document super call order for State.didChangeDependencies (flutter/flutter#185945)
2026-08-05 dkwingsmt@users.noreply.github.com Move examples of `flutter/widgets` widgets out from `flutter/material` (flutter/flutter#189532)
2026-08-05 93888664+ColeSpringer@users.noreply.github.com [web] Use thread local strike caches in skwasm (flutter/flutter#190048)
2026-08-05 43089218+chika3742@users.noreply.github.com doc: fix typo in see also section for PrimaryScrollController.maybeOf (flutter/flutter#190386)
2026-08-05 jason-simmons@users.noreply.github.com Migrate the shell unit tests from legacy Dart native functions to FFI (flutter/flutter#190473)
2026-08-05 47866232+chunhtai@users.noreply.github.com render proxy box now defaults baseline calculation to null (flutter/flutter#190269)
2026-08-05 36861262+QuncCccccc@users.noreply.github.com Update Widgets Localizations from Translation Console (flutter/flutter#190503)
2026-08-04 154381524+flutteractionsbot@users.noreply.github.com Revert: fix(tool): remove redundant --enable-experiment=record-use flag (flutter/flutter#190583)
2026-08-04 engine-flutter-autoroll@skia.org Roll Fuchsia Test Scripts from 1frGe_KltAJKkeyPg... to ltbuIH9Z3T_yOuigu... (flutter/flutter#190561)
2026-08-04 chris@bracken.jp iOS,macOS: add tsan and ubsan support for Swift (flutter/flutter#190497)
2026-08-04 34465683+rkishan516@users.noreply.github.com fix: update on_message_ to nullptr after window destroy so that dart gets destroy message  (flutter/flutter#185807)
2026-08-04 bkonyi@google.com [flutter_tools] Gracefully handle locked Windows files during clean (flutter/flutter#190095)
2026-08-04 chris@bracken.jp iOS,macOS: make Logger thread-safe, conform to Sendable (flutter/flutter#190488)
2026-08-04 chris@bracken.jp iOS: Eliminate use of IOSContextNoop in platform view tests (reland) (flutter/flutter#190509)
2026-08-04 kevmoo@users.noreply.github.com fix(tool): remove redundant --enable-experiment=record-use flag (flutter/flutter#190475)
2026-08-04 awolff@google.com android_hardware_smoke_test: Detect blank image failures or EGL initialization warnings and retry (flutter/flutter#190110)
2026-08-04 30870216+gaaclarke@users.noreply.github.com Bumps text gamma on windows to match skia. (flutter/flutter#190477)
2026-08-04 engine-flutter-autoroll@skia.org Roll Skia from 48b58ee222f1 to a8583a0a2c11 (2 revisions) (flutter/flutter#190537)
2026-08-04 kevmoo@users.noreply.github.com [tool][web] Intercept dart2wasm errors & append JS migration footers (flutter/flutter#190476)
2026-08-04 dacoharkes@google.com [record_use] Migrate IconTreeShaker to `package:record_use` (flutter/flutter#190225)
2026-08-04 s4bre.py@gmail.com Handle unexpected exceptions during Azure metadata detection (flutter/flutter#189457)
2026-08-04 15619084+vashworth@users.noreply.github.com Fix merge conflict from flutter/flutter#190369 (flutter/flutter#190544)
2026-08-04 15619084+vashworth@users.noreply.github.com Prepare device support symbols (flutter/flutter#190369)
2026-08-04 engine-flutter-autoroll@skia.org Roll Packages from ac87e65 to 3498b9d (1 revision) (flutter/flutter#190532)
2026-08-04 engine-flutter-autoroll@skia.org Roll Skia from a08d918ebd6a to 48b58ee222f1 (11 revisions) (flutter/flutter#190527)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC stuartmorgan@google.com,tarrinneal@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: desktop Running on desktop CICD Run CI/CD engine flutter/engine related. See also e: labels. platform-ios iOS applications specifically team-ios Owned by iOS platform team team-macos Owned by the macOS platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants