swiftlang / swift-corelibs-foundation

The Foundation Project, providing core utilities, internationalization, and OS independence
swift.org
Apache License 2.0
5.3k stars 1.14k forks source link

[SR-11323] Calendar is not thread-safe #3984

Open swift-ci opened 5 years ago

swift-ci commented 5 years ago
Previous ID SR-11323
Radar None
Original Reporter aulanov (JIRA User)
Type Bug
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 0 | |Component/s | Foundation | |Labels | Bug | |Assignee | None | |Priority | Medium | md5: 2773525e087aef23e6a04ba1cce9607d

is duplicated by:

Issue Description:

I'm getting unpredictable results when invoking Calendar.startOfDay() from parallel threads on the same Calendar object. This only happens on Linux. (I wasn't able to reproduce the problem on Darwin)

import Foundation
let cal = Calendar(identifier: .gregorian)
let queue = DispatchQueue(label: "test", attributes: .concurrent)
let date = Date()
let start = cal.startOfDay(for: date)
for _ in 0...10000 {
  queue.async {
    precondition(start == cal.startOfDay(for: date))
  }
}

$ swift run
Precondition failed: file /home/cal/Sources/cal/main.swift, line 8
$

spevans commented 5 years ago

https://github.com/apple/swift-corelibs-foundation/pull/2481

swift-ci commented 5 years ago

Comment by Andrey Ulanov (JIRA)

If you look at CFCalendar source code (https://github.com/apple/swift-corelibs-foundation/blob/master/CoreFoundation/Locale.subproj/CFCalendar.c) you'll see other code that is not thread-safe since it uses calendar->_cal as a temporary storage. The PR above only fixes the CFCalendarGetTimeRangeOfUnit invocation. I can see that at least the following CFCalendar functions will have the same problem:

CFCalendarAddComponentsV()

CFCalendarGetComponentDifferenceV()