Skip to content

SR-13979: Calendar.nextDate() segmentation fault #2957

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ CF_PRIVATE Boolean __CFAllocatorRespectsHintZeroWhenAllocating(CFAllocatorRef _N
static CFOptionFlags _CFAllocatorHintZeroWhenAllocating = 1;

CF_CROSS_PLATFORM_EXPORT Boolean _CFCalendarGetNextWeekend(CFCalendarRef calendar, _CFCalendarWeekendRange *range);
CF_CROSS_PLATFORM_EXPORT void _CFCalendarEnumerateDates(CFCalendarRef calendar, CFDateRef start, CFDateComponentsRef matchingComponents, CFOptionFlags opts, void (^block)(CFDateRef, Boolean, Boolean*));
CF_CROSS_PLATFORM_EXPORT void _CFCalendarEnumerateDates(CFCalendarRef calendar, CFDateRef start, CFDateComponentsRef matchingComponents, CFOptionFlags opts, void (^block)(CFDateRef _Nullable, Boolean, Boolean*));
CF_EXPORT void CFCalendarSetGregorianStartDate(CFCalendarRef calendar, CFDateRef _Nullable date);
CF_EXPORT _Nullable CFDateRef CFCalendarCopyGregorianStartDate(CFCalendarRef calendar);

Expand Down
2 changes: 1 addition & 1 deletion CoreFoundation/Locale.subproj/CFCalendar_Enumerate.c
Original file line number Diff line number Diff line change
Expand Up @@ -2123,7 +2123,7 @@ static CFDateRef _Nullable _CFCalendarCreateAdjustedDateForMismatches(CFCalendar
#pragma mark -
#pragma mark Enumerate Entry Point

CF_CROSS_PLATFORM_EXPORT void _CFCalendarEnumerateDates(CFCalendarRef calendar, CFDateRef start, CFDateComponentsRef matchingComponents, CFOptionFlags opts, void (^block)(CFDateRef, Boolean, Boolean*)) {
CF_CROSS_PLATFORM_EXPORT void _CFCalendarEnumerateDates(CFCalendarRef calendar, CFDateRef start, CFDateComponentsRef matchingComponents, CFOptionFlags opts, void (^block)(CFDateRef _Nullable, Boolean, Boolean*)) {
if (!start || !_CFCalendarVerifyCalendarOptions(opts) || !_CFCalendarVerifyCFDateComponentsValues(calendar, matchingComponents)) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion CoreFoundation/Locale.subproj/CFCalendar_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ CF_PRIVATE _Nullable CFDateRef _CFCalendarCreateStartDateForTimeRangeOfUnitForDa
CF_PRIVATE _Nullable CFDateIntervalRef _CFCalendarCreateDateInterval(CFAllocatorRef allocator, CFCalendarRef calendar, CFCalendarUnit unit, CFDateRef date);
CF_PRIVATE _Nullable CFDateRef _CFCalendarCreateDateByAddingValueOfUnitToDate(CFCalendarRef calendar, CFIndex val, CFCalendarUnit unit, CFDateRef date);

CF_CROSS_PLATFORM_EXPORT void _CFCalendarEnumerateDates(CFCalendarRef calendar, CFDateRef start, CFDateComponentsRef matchingComponents, CFOptionFlags opts, void (^block)(CFDateRef, Boolean, Boolean*));
CF_CROSS_PLATFORM_EXPORT void _CFCalendarEnumerateDates(CFCalendarRef calendar, CFDateRef start, CFDateComponentsRef matchingComponents, CFOptionFlags opts, void (^block)(CFDateRef _Nullable, Boolean, Boolean*));

CF_EXPORT void CFCalendarSetGregorianStartDate(CFCalendarRef calendar, CFDateRef _Nullable date);
CF_EXPORT _Nullable CFDateRef CFCalendarCopyGregorianStartDate(CFCalendarRef calendar);
Expand Down
4 changes: 4 additions & 0 deletions Sources/Foundation/NSCalendar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,10 @@ open class NSCalendar : NSObject, NSCopying, NSSecureCoding {

withoutActuallyEscaping(block) { (nonescapingBlock) in
_CFCalendarEnumerateDates(_cfObject, start._cfObject, comps._createCFDateComponents(), CFOptionFlags(opts.rawValue)) { (cfDate, exact, stop) in
guard let cfDate = cfDate else {
stop.pointee = true
return
}
var ourStop: ObjCBool = false
nonescapingBlock(cfDate._swiftObject, exact, &ourStop)
if ourStop.boolValue {
Expand Down
21 changes: 21 additions & 0 deletions Tests/Foundation/Tests/TestCalendar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,26 @@ class TestCalendar: XCTestCase {
XCTAssertGreaterThan(cal.eraSymbols.count, 0)
}

func test_nextDate() throws {
var calendar = Calendar.current
calendar.timeZone = try XCTUnwrap(TimeZone(identifier: "US/Pacific"))
let date_20200101 = try XCTUnwrap(calendar.date(from: DateComponents(year: 2020, month: 01, day: 1)))

do {
let expected = try XCTUnwrap(calendar.date(from: DateComponents(year: 2020, month: 01, day: 2, hour: 0)))
let components = DateComponents(year: 2020, month: 1, day: 2, hour: 0, minute: 0, second: 0)
let next = calendar.nextDate(after: date_20200101, matching: components, matchingPolicy: .nextTimePreservingSmallerComponents, direction: .forward)
XCTAssertEqual(next, expected)
}

do {
// SR-13979 - Check nil result when no valid nextDate
let components = DateComponents(year: 2019, month: 2, day: 1, hour: 0, minute: 0, second: 0)
let next = calendar.nextDate(after: date_20200101, matching: components, matchingPolicy: .nextTimePreservingSmallerComponents, direction: .forward)
XCTAssertNil(next)
}
}

static var allTests: [(String, (TestCalendar) -> () throws -> Void)] {
return [
("test_allCalendars", test_allCalendars),
Expand All @@ -287,6 +307,7 @@ class TestCalendar: XCTestCase {
("test_hashing", test_hashing),
("test_dateFromDoesntMutate", test_dateFromDoesntMutate),
("test_sr10638", test_sr10638),
("test_nextDate", test_nextDate),
]
}
}