Vedant Kumar 8c4a65b9b2 [ubsan] Check implicit casts in ObjC for-in statements
Check that the implicit cast from `id` used to construct the element
variable in an ObjC for-in statement is valid.

This check is included as part of a new `objc-cast` sanitizer, outside
of the main 'undefined' group, as (IIUC) the behavior it's checking for
is not technically UB.

The check can be extended to cover other kinds of invalid casts in ObjC.

Partially addresses: rdar://12903059, rdar://9542496

Differential Revision: https://reviews.llvm.org/D71491
2020-07-13 15:11:18 -07:00

66 lines
2.1 KiB
Objective-C

// RUN: %clang_cc1 %s -verify -o /dev/null
// RUN: %clang_cc1 %s -triple x86_64-apple-darwin -emit-llvm -fsanitize=objc-cast -o - | FileCheck %s
void p(const char*, ...);
@interface NSArray
+(NSArray*) arrayWithObjects: (id) first, ...;
-(unsigned) count;
@end
@interface NSString
-(const char*) cString;
@end
#define S(n) @#n
#define L1(n) S(n+0),S(n+1)
#define L2(n) L1(n+0),L1(n+2)
#define L3(n) L2(n+0),L2(n+4)
#define L4(n) L3(n+0),L3(n+8)
#define L5(n) L4(n+0),L4(n+16)
#define L6(n) L5(n+0),L5(n+32)
// CHECK-LABEL: define void @t0
void t0() {
NSArray *array = [NSArray arrayWithObjects: L1(0), (void*)0];
p("array.length: %d\n", [array count]);
unsigned index = 0;
for (NSString *i in array) { // expected-warning {{collection expression type 'NSArray *' may not respond}}
// CHECK: [[expectedCls:%.*]] = load %struct._class_t*, {{.*}}, !nosanitize
// CHECK-NEXT: [[kindOfClassSel:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES{{.*}}, !nosanitize
// CHECK-NEXT: [[expectedClsI8:%.*]] = bitcast %struct._class_t* [[expectedCls]] to i8*, !nosanitize
// CHECK-NEXT: [[isCls:%.*]] = call zeroext i1 bitcast {{.*}}@objc_msgSend to i1 (i8*, i8*, {{.*}})(i8* [[theItem:%.*]], i8* [[kindOfClassSel]], i8* [[expectedClsI8]]), !nosanitize
// CHECK: br i1 [[isCls]]
// CHECK: ptrtoint i8* [[theItem]] to i64, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_invalid_objc_cast
// CHECK-NEXT: unreachable, !nosanitize
// CHECK: bitcast i8* [[theItem]]
p("element %d: %s\n", index++, [i cString]);
}
}
void t1() {
NSArray *array = [NSArray arrayWithObjects: L6(0), (void*)0];
p("array.length: %d\n", [array count]);
unsigned index = 0;
for (NSString *i in array) { // expected-warning {{collection expression type 'NSArray *' may not respond}}
index++;
if (index == 10)
continue;
p("element %d: %s\n", index, [i cString]);
if (index == 55)
break;
}
}
// rdar://problem/9027663
void t2(NSArray *array) {
for (NSArray *array in array) { // expected-warning {{collection expression type 'NSArray *' may not respond}}
}
}