// RUN: rm -rf %t // RUN: mkdir -p %t // RUN: %S/../../utils/gyb %s -o %t/ArrayTraps.swift // RUN: %S/../../utils/line-directive %t/ArrayTraps.swift -- %target-build-swift %t/ArrayTraps.swift -o %t/a.out_Debug // RUN: %S/../../utils/line-directive %t/ArrayTraps.swift -- %target-build-swift %t/ArrayTraps.swift -o %t/a.out_Release -O // // RUN: %S/../../utils/line-directive %t/ArrayTraps.swift -- %target-run %t/a.out_Debug // RUN: %S/../../utils/line-directive %t/ArrayTraps.swift -- %target-run %t/a.out_Release // XFAIL: linux import StdlibUnittest %{ # We test for bounds-checking traps for both reading and writing # both single elements and slices of all three different array # types. array_types = ('Array', 'ContiguousArray', 'ArraySlice', '_UnitTestArray') def bounds_trap(index, expr_to_write): global io return 'expectCrashLater()\n' + ( 'let x = a[%s]' % index if io == 'read' else 'a[%s] = %s' % (index, expr_to_write)) }% % for ArrayTy in array_types: var ${ArrayTy}Traps = TestSuite("${ArrayTy}Traps") % for io in ['read', 'write']: ${ArrayTy}Traps.test("bounds1/${io}") { var a: ${ArrayTy} = [] ${bounds_trap(index='0', expr_to_write='1')} } ${ArrayTy}Traps.test("bounds2/${io}") { var a: ${ArrayTy} = [] ${bounds_trap(index='100', expr_to_write='1')} } ${ArrayTy}Traps.test("bounds3/${io}") { var a: ${ArrayTy} = [ 10, 20, 30 ] ${bounds_trap(index='3', expr_to_write='1')} } ${ArrayTy}Traps.test("sliceBounds0/${io}") { var a: ${ArrayTy} = [] ${bounds_trap(index='-1..<1', expr_to_write='ArraySlice()')} } ${ArrayTy}Traps.test("sliceBounds1/${io}") { var a: ${ArrayTy} = [ 1 ] ${bounds_trap(index='-1..<1', expr_to_write='ArraySlice()')} } ${ArrayTy}Traps.test("sliceBounds2/${io}") { var a: ${ArrayTy} = [ 1 ] ${bounds_trap(index='0..<2', expr_to_write='ArraySlice()')} } ${ArrayTy}Traps.test("sliceBounds3/${io}") { var a: ${ArrayTy} = [ 1 ] ${bounds_trap(index='1..<2', expr_to_write='ArraySlice()')} } % end ${ArrayTy}Traps.test("PopFromEmpty") { var a: ${ArrayTy} = [] expectCrashLater() a.removeLast() } % for index in -1, 2: ${ArrayTy}Traps.test("${'insert(_:atIndex:)/%s' % index}") { var a: ${ArrayTy} = [42] expectCrashLater() a.insert(3, atIndex: ${index}) } % end % for index in -1, 1, 2: ${ArrayTy}Traps.test("${'removeAtIndex(_:)/%s' % index}") { var a: ${ArrayTy} = [42] expectCrashLater() a.removeAtIndex(${index}) } % end % end class Base { } class Derived : Base { } class Derived2 : Derived { } ArrayTraps.test("downcast1") { let ba: [Base] = [ Derived(), Base() ] let da = ba as! [Derived] let d0 = da[0] expectCrashLater() da[1] } import Foundation ArrayTraps.test("downcast2") { let a: [AnyObject] = [ "String", 1 ] let sa = a as! [NSString] let s0 = sa[0] expectCrashLater() sa[1] } ArrayTraps.test("downcast3") { let ba: [Base] = [ Derived2(), Derived(), Base() ] let d2a = ba as! [Derived2] let d2a0 = d2a[0] let d1a = d2a as [Derived] let d1a0 = d1a[0] let d1a1 = d1a[1] expectCrashLater() d1a[2] } @objc protocol ObjCProto { } class ObjCBase : NSObject, ObjCProto { } class ObjCDerived : ObjCBase { } ArrayTraps.test("downcast4") { let ba: [ObjCProto] = [ ObjCDerived(), ObjCBase() ] let da = ba as! [ObjCDerived] let d0 = da[0] expectCrashLater() da[1] } ArrayTraps.test("unsafeLength") { var a = [ 42, 77, 88 ] expectEqual(42, a.withUnsafeBufferPointer({ $0[0] })) expectCrashLater() a.withUnsafeBufferPointer { UnsafeBufferPointer(start: $0.baseAddress, count: -1) } } ArrayTraps.test("bounds_with_downcast") .crashOutputMatches(_isDebugAssertConfiguration() ? "fatal error: Array index out of range" : "") .code { let ba: [Base] = [ Derived(), Base() ] let da = ba as! [Derived] expectCrashLater() let x = da[2] } var ArraySemanticOptzns = TestSuite("ArraySemanticOptzns") class BaseClass { } class ElementClass : BaseClass { var val: String init(_ x: String) { val = x } } class ViolateInoutSafeySwitchToObjcBuffer { final var anArray: [ElementClass] = [] let nsArray = NSArray( objects: ElementClass("a"), ElementClass("b"), ElementClass("c")) @inline(never) func accessArrayViaInoutVolation() { anArray = _convertNSArrayToArray(nsArray) } @inline(never) func runLoop(inout A: [ElementClass]) { // Simulate what happens if we hoist array properties out of a loop and the // loop calls a function that violates inout safety and overrides the array. let isNativeNoTypeCheck = A._getArrayPropertyIsNativeNoTypeCheck() for i in 0..