1 // RUN: %clang --analyze -Xanalyzer -analyzer-checker=osx.cocoa.IncompatibleMethodTypes,osx.coreFoundation.CFRetainRelease -Xclang -verify %s 2 3 #include "InlineObjCInstanceMethod.h" 4 5 typedef const struct __CFString * CFStringRef; 6 typedef const void * CFTypeRef; 7 extern CFTypeRef CFRetain(CFTypeRef cf); 8 extern void CFRelease(CFTypeRef cf); 9 extern CFStringRef getString(void); 10 11 // Method is defined in the parent; called through self. 12 @interface MyParent : NSObject 13 - (int)getInt; 14 - (const struct __CFString *) testCovariantReturnType __attribute__((cf_returns_retained)); 15 @end 16 @implementation MyParent 17 - (int)getInt { 18 return 0; 19 } 20 21 - (CFStringRef) testCovariantReturnType __attribute__((cf_returns_retained)) { 22 CFStringRef Str = ((void*)0); 23 Str = getString(); 24 if (Str) { 25 CFRetain(Str); 26 } 27 return Str; 28 } 29 30 @end 31 32 @interface MyClass : MyParent 33 @end 34 @implementation MyClass 35 - (int)testDynDispatchSelf { 36 int y = [self getInt]; 37 return 5/y; // expected-warning {{Division by zero}} 38 } 39 40 // Get the dynamic type info from a cast (from id to MyClass*). 41 + (int)testAllocInit { 42 MyClass *a = [[self alloc] init]; 43 return 5/[a getInt]; // expected-warning {{Division by zero}} 44 } 45 46 // Method is called on inited object. 47 + (int)testAllocInit2 { 48 MyClass *a = [[MyClass alloc] init]; 49 return 5/[a getInt]; // expected-warning {{Division by zero}} 50 } 51 52 // Method is called on a parameter. 53 + (int)testParam: (MyClass*) a { 54 return 5/[a getInt]; // expected-warning {{Division by zero}} 55 } 56 57 // Method is called on a parameter of unnown type. 58 + (int)testParamUnknownType: (id) a { 59 return 5/[a getInt]; // no warning 60 } 61 62 @end 63 64 // TODO: When method is inlined, the attribute reset should be visible. 65 @interface TestSettingAnAttributeInCallee : NSObject { 66 int _attribute; 67 } 68 - (void) method2; 69 @end 70 71 @implementation TestSettingAnAttributeInCallee 72 - (int) method1 { 73 [self method2]; 74 return 5/_attribute; // expected-warning {{Division by zero}} 75 } 76 77 - (void) method2 { 78 _attribute = 0; 79 } 80 @end 81 82 @interface TestSettingAnAttributeInCaller : NSObject { 83 int _attribute; 84 } 85 - (int) method2; 86 @end 87 88 @implementation TestSettingAnAttributeInCaller 89 - (void) method1 { 90 _attribute = 0; 91 [self method2]; 92 } 93 94 - (int) method2 { 95 return 5/_attribute; // expected-warning {{Division by zero}} 96 } 97 @end 98 99 100 // Don't crash if we don't know the receiver's region. 101 void randomlyMessageAnObject(MyClass *arr[], int i) { 102 (void)[arr[i] getInt]; 103 } 104 105 106 @interface EvilChild : MyParent 107 - (id)getInt; 108 - (const struct __CFString *) testCovariantReturnType __attribute__((cf_returns_retained)); 109 @end 110 111 @implementation EvilChild 112 - (id)getInt { // expected-warning {{types are incompatible}} 113 return self; 114 } 115 - (CFStringRef) testCovariantReturnType __attribute__((cf_returns_retained)) { 116 CFStringRef Str = ((void*)0); 117 Str = getString(); 118 if (Str) { 119 CFRetain(Str); 120 } 121 return Str; 122 } 123 124 @end 125 126 int testNonCovariantReturnType() { 127 MyParent *obj = [[EvilChild alloc] init]; 128 129 // Devirtualization allows us to directly call -[EvilChild getInt], but 130 // that returns an id, not an int. There is an off-by-default warning for 131 // this, -Woverriding-method-mismatch, and an on-by-default analyzer warning, 132 // osx.cocoa.IncompatibleMethodTypes. This code would probably crash at 133 // runtime, but at least the analyzer shouldn't crash. 134 int x = 1 + [obj getInt]; 135 136 [obj release]; 137 return 5/(x-1); // no-warning 138 } 139 140 int testCovariantReturnTypeNoErrorSinceTypesMatch() { 141 MyParent *obj = [[EvilChild alloc] init]; 142 143 CFStringRef S = ((void*)0); 144 S = [obj testCovariantReturnType]; 145 if (S) 146 CFRelease(S); 147 CFRelease(obj); 148 } 149