Describe the bug
Accessing Calendar from FoundationEssentials rapidly and concurrently can cause various thread safety issues on Windows and macOS, including access violations and heap corruption.
To Reproduce
#if canImport(FoundationEssentials)
import FoundationEssentials
#else
import Foundation
#endif
import Dispatch
@main
struct Bug {
static func main() {
DispatchQueue.concurrentPerform(iterations: 100) { i in
let calendar = Calendar.current
let timeZone = TimeZone.current
let date = DateComponents(calendar: calendar, timeZone: timeZone)
}
}
}
When debugging with LLDB, this output appears:
(lldb) n
Process 24336 stopped
* thread #11, name = 'com.apple.root.default-qos', stop reason = Exception 0xc0000005 encountered at address 0x7ff84bf720c9: Access violation reading location 0xb1805d80
frame #0: 0x00007ff84bf720c9 swiftCore.dll`swift_retain + 41
swiftCore.dll`swift_retain:
-> 0x7ff84bf720c9 <+41>: movq 0x8(%r8), %rax
0x7ff84bf720cd <+45>: nopl (%rax)
0x7ff84bf720d0 <+48>: movq %rax, %r10
0x7ff84bf720d3 <+51>: addq %r9, %r10
Target 0: (Bug.exe) stopped.
(lldb) bt
* thread #11, name = 'com.apple.root.default-qos', stop reason = Exception 0xc0000005 encountered at address 0x7ff84bf720c9: Access violation reading location 0xb1805d80
* frame #0: 0x00007ff84bf720c9 swiftCore.dll`swift_retain + 41
frame #1: 0x00007ff7803313cd Bug.exe`closure #1 in static Bug.main(i=4) at Bug.swift:11:69
frame #2: 0x00007ff8e5209440 swiftDispatch.dll`static DispatchQueue.concurrentPerform(iterations:execute:) + 352
frame #3: 0x00007ff8e520ae43 swiftDispatch.dll`Dispatch.DispatchQueue.AutoreleaseFrequency.hashValue.getter : Swift.Int + 67
frame #4: 0x00007ff8d6f310fe dispatch.dll`
frame #5: 0x00007ff8d6f44dd2 dispatch.dll`_dispatch_prohibit_transition_to_multithreaded + 8802
frame #6: 0x00007ff9116b37b0 ucrtbase.dll`wcsrchr + 336
frame #7: 0x00007ff9130ce957 kernel32.dll`BaseThreadInitThunk + 23
frame #8: 0x00007ff914b0421c ntdll.dll`RtlUserThreadStart + 44
Expected behavior
No access violations occur during the execution of the program
Configuration
- Swift Version: Swift 6.3 (Release)
- OS: Windows and macOS
- OS Version: Windows 11 (25H2) and macOS 26
Regression information:
This issue also occurs on Swift 6.2.3, but I haven't tested other versions.
Additional context
- I saw the recent PR 'Replace LockedState with Mutex' which updated the Calendar cache; I do not know if it fixes this issue.
- The program where I first encountered this bug exited silently with the Heap Corruption status code on Windows and the environment variable
_NO_DEBUG_HEAP=1 was needed to reproduce the issue while debugging with LLDB. An excerpt of the LLDB output is below:
(lldb) n
Process 29660 stopped
* thread #10, name = 'com.apple.root.default-qos.overcommit', stop reason = Exception 0x80000003 encountered at address 0x7ff914b98f28
frame #0: 0x00007ff914b98f29 ntdll.dll`LdrResSearchResource + 2041
ntdll.dll`LdrResSearchResource:
-> 0x7ff914b98f29 <+2041>: jmp 0x7ff914b98f37 ; <+2055>
0x7ff914b98f2b <+2043>: movq 0xf8(%rsp), %rdi
0x7ff914b98f33 <+2051>: movl 0x20(%rsp), %ebx
0x7ff914b98f37 <+2055>: movl %ebx, 0x30(%rsp)
Target 0: (Generator.exe) stopped.
(lldb) bt
* thread #10, name = 'com.apple.root.default-qos.overcommit', stop reason = Exception 0x80000003 encountered at address 0x7ff914b98f28
* frame #0: 0x00007ff914b98f29 ntdll.dll`LdrResSearchResource + 2041
frame #1: 0x00007ff914b31db2 ntdll.dll`RtlSetProcessPreferredUILanguages + 2978
frame #2: 0x00007ff914c1d86a ntdll.dll`RtlLengthCurrentClearRunForwardEx + 1050
frame #3: 0x00007ff914b2a39b ntdll.dll`RtlCreateUnicodeString + 9083
frame #4: 0x00007ff914b26c45 ntdll.dll`RtlFreeHeap + 645
frame #5: 0x00007ff9116ce0fb ucrtbase.dll`_free_base + 27
frame #6: 0x00007ff84bf7337f swiftCore.dll`swift_unownedCheck + 287
frame #7: 0x00007ff84bf73c3a swiftCore.dll`swift_weakTakeAssign + 378
frame #8: 0x00007ff84bcac551 swiftCore.dll`Swift._DictionaryStorage.deinit + 257
frame #9: 0x00007ff84bcac6e9 swiftCore.dll`Swift._DictionaryStorage.__deallocating_deinit + 9
frame #10: 0x00007ff84bf7337f swiftCore.dll`swift_unownedCheck + 287
frame #11: 0x00007ff84bf73c3a swiftCore.dll`swift_weakTakeAssign + 378
frame #12: 0x00007ff84342d6d9 FoundationEssentials.dll`_timeZoneIdentifier(forWindowsIdentifier:) + 617
frame #13: 0x00007ff84342e246 FoundationEssentials.dll`_timeZoneIdentifier(forWindowsIdentifier:) + 3542
frame #14: 0x00007ff843191ab0 FoundationEssentials.dll`LockedState.withLockUnchecked(_:) + 80
frame #15: 0x00007ff843191a59 FoundationEssentials.dll`LockedState.withLock(_:) + 9
frame #16: 0x00007ff84342e1e4 FoundationEssentials.dll`_timeZoneIdentifier(forWindowsIdentifier:) + 3444
frame #17: 0x00007ff843242c7c FoundationEssentials.dll`FoundationEssentials.Calendar.Component.nextHigherUnit.getter : Swift.Optional<FoundationEssentials.Calendar.Component> + 31116
frame #18: 0x00007ff843253046 FoundationEssentials.dll`FoundationEssentials.Calendar.Component.nextHigherUnit.getter : Swift.Optional<FoundationEssentials.Calendar.Component> + 97622
frame #19: 0x00007ff8432301e6 FoundationEssentials.dll`_calendarICUClass() + 838
Describe the bug
Accessing
CalendarfromFoundationEssentialsrapidly and concurrently can cause various thread safety issues on Windows and macOS, including access violations and heap corruption.To Reproduce
When debugging with LLDB, this output appears:
Expected behavior
No access violations occur during the execution of the program
Configuration
Regression information:
This issue also occurs on Swift 6.2.3, but I haven't tested other versions.
Additional context
_NO_DEBUG_HEAP=1was needed to reproduce the issue while debugging with LLDB. An excerpt of the LLDB output is below: