From ca988933a94b4fa9d835b4205ecdb91524322b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez=20Troiti=C3=B1o?= Date: Thu, 30 Aug 2018 15:02:52 -0700 Subject: [PATCH] Fix argument order for CFArraySetValueAtIndex. The Swift dispatching of CFArraySetValueAtIndex had the arguments for value and index switched around. If someone creates a Swift NSArray which is eventually bridged to CFArray, and some other piece calls CFArraySetValueAtIndex, CF_SWIFT_FUNCDISPATCHV will delegate to the Swift method, but will send a pointer where CFIndex is expected, and a CFIndex where a pointer is expected, probably causing a segmentation fault. The test tries to simplify the scenario (not easy to create the right conditions) and uses unsafeBitCast (which is the same that happens in the internal _cfObject). The test crashes before the patch is applied. --- CoreFoundation/Collections.subproj/CFArray.c | 2 +- TestFoundation/TestNSArray.swift | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CoreFoundation/Collections.subproj/CFArray.c b/CoreFoundation/Collections.subproj/CFArray.c index 58a5f29310..987799831f 100644 --- a/CoreFoundation/Collections.subproj/CFArray.c +++ b/CoreFoundation/Collections.subproj/CFArray.c @@ -628,7 +628,7 @@ void CFArrayAppendValue(CFMutableArrayRef array, const void *value) { } void CFArraySetValueAtIndex(CFMutableArrayRef array, CFIndex idx, const void *value) { - CF_SWIFT_FUNCDISPATCHV(CFArrayGetTypeID(), void, (CFSwiftRef)array, NSMutableArray.setObject, idx, value); + CF_SWIFT_FUNCDISPATCHV(CFArrayGetTypeID(), void, (CFSwiftRef)array, NSMutableArray.setObject, value, idx); CF_OBJC_FUNCDISPATCHV(CFArrayGetTypeID(), void, (NSMutableArray *)array, setObject:(id)value atIndex:(NSUInteger)idx); __CFGenericValidateType(array, CFArrayGetTypeID()); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); diff --git a/TestFoundation/TestNSArray.swift b/TestFoundation/TestNSArray.swift index b37aea9aa4..2de71b948a 100644 --- a/TestFoundation/TestNSArray.swift +++ b/TestFoundation/TestNSArray.swift @@ -7,6 +7,8 @@ // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // +import CoreFoundation + class TestNSArray : XCTestCase { static var allTests: [(String, (TestNSArray) -> () throws -> Void)] { @@ -42,6 +44,7 @@ class TestNSArray : XCTestCase { ("test_insertObjectsAtIndexes", test_insertObjectsAtIndexes), ("test_replaceObjectsAtIndexesWithObjects", test_replaceObjectsAtIndexesWithObjects), ("test_pathsMatchingExtensions", test_pathsMatchingExtensions), + ("test_arrayUsedAsCFArrayInvokesArrayMethods", test_arrayUsedAsCFArrayInvokesArrayMethods), ] } @@ -794,6 +797,14 @@ class TestNSArray : XCTestCase { XCTAssertEqual(match5, []) } + func test_arrayUsedAsCFArrayInvokesArrayMethods() { + let number = 789 as NSNumber + let array = NSMutableArray(array: [123, 456]) + CFArraySetValueAtIndex(unsafeBitCast(array, to: CFMutableArray.self), 1, UnsafeRawPointer(Unmanaged.passUnretained(number).toOpaque())) + XCTAssertEqual(array[0] as! NSNumber, 123 as NSNumber) + XCTAssertEqual(array[1] as! NSNumber, 789 as NSNumber) + } + private func createTestFile(_ path: String, _contents: Data) -> String? { let tempDir = NSTemporaryDirectory() + "TestFoundation_Playground_" + NSUUID().uuidString + "/" do {