1// RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability -verify %s 2 3#define nil 0 4#define BOOL int 5 6@protocol NSObject 7+ (id)alloc; 8- (id)init; 9@end 10 11@protocol NSCopying 12@end 13 14__attribute__((objc_root_class)) 15@interface 16NSObject<NSObject> 17@end 18 19@interface NSString : NSObject<NSCopying> 20- (BOOL)isEqualToString : (NSString *_Nonnull)aString; 21- (NSString *)stringByAppendingString:(NSString *_Nonnull)aString; 22@end 23 24@interface TestObject : NSObject 25- (int *_Nonnull)returnsNonnull; 26- (int *_Nullable)returnsNullable; 27- (int *)returnsUnspecified; 28- (void)takesNonnull:(int *_Nonnull)p; 29- (void)takesNullable:(int *_Nullable)p; 30- (void)takesUnspecified:(int *)p; 31@property(readonly, strong) NSString *stuff; 32@end 33 34TestObject * getUnspecifiedTestObject(); 35TestObject *_Nonnull getNonnullTestObject(); 36TestObject *_Nullable getNullableTestObject(); 37 38int getRandom(); 39 40typedef struct Dummy { int val; } Dummy; 41 42void takesNullable(Dummy *_Nullable); 43void takesNonnull(Dummy *_Nonnull); 44void takesUnspecified(Dummy *); 45 46Dummy *_Nullable returnsNullable(); 47Dummy *_Nonnull returnsNonnull(); 48Dummy *returnsUnspecified(); 49int *_Nullable returnsNullableInt(); 50 51template <typename T> T *eraseNullab(T *p) { return p; } 52 53void takesAttrNonnull(Dummy *p) __attribute((nonnull(1))); 54 55void testBasicRules() { 56 Dummy *p = returnsNullable(); 57 int *ptr = returnsNullableInt(); 58 // Make every dereference a different path to avoid sinks after errors. 59 switch (getRandom()) { 60 case 0: { 61 Dummy &r = *p; // expected-warning {{}} 62 } break; 63 case 1: { 64 int b = p->val; // expected-warning {{}} 65 } break; 66 case 2: { 67 int stuff = *ptr; // expected-warning {{}} 68 } break; 69 case 3: 70 takesNonnull(p); // expected-warning {{}} 71 break; 72 case 4: { 73 Dummy d; 74 takesNullable(&d); 75 Dummy dd(d); 76 break; 77 } 78 case 5: takesAttrNonnull(p); break; // expected-warning {{Nullable pointer is passed to}} 79 default: { Dummy d = *p; } break; // expected-warning {{Nullable pointer is dereferenced}} 80 } 81 if (p) { 82 takesNonnull(p); 83 if (getRandom()) { 84 Dummy &r = *p; 85 } else { 86 int b = p->val; 87 } 88 } 89 Dummy *q = 0; 90 if (getRandom()) { 91 takesNullable(q); 92 takesNonnull(q); // expected-warning {{}} 93 } 94 Dummy a; 95 Dummy *_Nonnull nonnull = &a; 96 nonnull = q; // expected-warning {{}} 97 q = &a; 98 takesNullable(q); 99 takesNonnull(q); 100} 101 102void testMultiParamChecking(Dummy *_Nonnull a, Dummy *_Nullable b, 103 Dummy *_Nonnull c); 104 105void testArgumentTracking(Dummy *_Nonnull nonnull, Dummy *_Nullable nullable) { 106 Dummy *p = nullable; 107 Dummy *q = nonnull; 108 switch(getRandom()) { 109 case 1: nonnull = p; break; // expected-warning {{}} 110 case 2: p = 0; break; 111 case 3: q = p; break; 112 case 4: testMultiParamChecking(nonnull, nullable, nonnull); break; 113 case 5: testMultiParamChecking(nonnull, nonnull, nonnull); break; 114 case 6: testMultiParamChecking(nonnull, nullable, nullable); break; // expected-warning {{}} 115 case 7: testMultiParamChecking(nullable, nullable, nonnull); // expected-warning {{}} 116 case 8: testMultiParamChecking(nullable, nullable, nullable); // expected-warning {{}} 117 case 9: testMultiParamChecking((Dummy *_Nonnull)0, nullable, nonnull); break; 118 } 119} 120 121Dummy *_Nonnull testNullableReturn(Dummy *_Nullable a) { 122 Dummy *p = a; 123 return p; // expected-warning {{}} 124} 125 126Dummy *_Nonnull testNullReturn() { 127 Dummy *p = 0; 128 return p; // expected-warning {{}} 129} 130 131void testObjCMessageResultNullability() { 132 // The expected result: the most nullable of self and method return type. 133 TestObject *o = getUnspecifiedTestObject(); 134 int *shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNonnull]; 135 switch (getRandom()) { 136 case 0: 137 // The core analyzer assumes that the receiver is non-null after a message 138 // send. This is to avoid some false positives, and increase performance 139 // but it also reduces the coverage and makes this checker unable to reason 140 // about the nullness of the receiver. 141 [o takesNonnull:shouldBeNullable]; // No warning expected. 142 break; 143 case 1: 144 shouldBeNullable = 145 [eraseNullab(getNullableTestObject()) returnsUnspecified]; 146 [o takesNonnull:shouldBeNullable]; // No warning expected. 147 break; 148 case 3: 149 shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable]; 150 [o takesNonnull:shouldBeNullable]; // expected-warning {{}} 151 break; 152 case 4: 153 shouldBeNullable = [eraseNullab(getNonnullTestObject()) returnsNullable]; 154 [o takesNonnull:shouldBeNullable]; // expected-warning {{}} 155 break; 156 case 5: 157 shouldBeNullable = 158 [eraseNullab(getUnspecifiedTestObject()) returnsNullable]; 159 [o takesNonnull:shouldBeNullable]; // expected-warning {{}} 160 break; 161 case 6: 162 shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable]; 163 [o takesNonnull:shouldBeNullable]; // expected-warning {{}} 164 break; 165 case 7: { 166 int *shouldBeNonnull = [eraseNullab(getNonnullTestObject()) returnsNonnull]; 167 [o takesNonnull:shouldBeNonnull]; 168 } break; 169 } 170} 171 172void testCast() { 173 Dummy *p = (Dummy * _Nonnull)returnsNullable(); 174 takesNonnull(p); 175} 176 177void testInvalidPropagation() { 178 Dummy *p = returnsUnspecified(); 179 takesNullable(p); 180 takesNonnull(p); 181} 182 183void onlyReportFirstPreconditionViolationOnPath() { 184 Dummy *p = returnsNullable(); 185 takesNonnull(p); // expected-warning {{}} 186 takesNonnull(p); // No warning. 187 // The first warning was not a sink. The analysis expected to continue. 188 int i = 0; 189 i = 5 / i; // expected-warning {{Division by zero}} 190 (void)i; 191} 192 193Dummy *_Nonnull doNotWarnWhenPreconditionIsViolatedInTopFunc( 194 Dummy *_Nonnull p) { 195 if (!p) { 196 Dummy *ret = 197 0; // avoid compiler warning (which is not generated by the analyzer) 198 if (getRandom()) 199 return ret; // no warning 200 else 201 return p; // no warning 202 } else { 203 return p; 204 } 205} 206 207Dummy *_Nonnull doNotWarnWhenPreconditionIsViolated(Dummy *_Nonnull p) { 208 if (!p) { 209 Dummy *ret = 210 0; // avoid compiler warning (which is not generated by the analyzer) 211 if (getRandom()) 212 return ret; // no warning 213 else 214 return p; // no warning 215 } else { 216 return p; 217 } 218} 219 220void testPreconditionViolationInInlinedFunction(Dummy *p) { 221 doNotWarnWhenPreconditionIsViolated(p); 222} 223 224void inlinedNullable(Dummy *_Nullable p) { 225 if (p) return; 226} 227void inlinedNonnull(Dummy *_Nonnull p) { 228 if (p) return; 229} 230void inlinedUnspecified(Dummy *p) { 231 if (p) return; 232} 233 234Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) { 235 switch (getRandom()) { 236 case 1: inlinedNullable(p); break; 237 case 2: inlinedNonnull(p); break; 238 case 3: inlinedUnspecified(p); break; 239 } 240 if (getRandom()) 241 takesNonnull(p); // no-warning 242 243 if (getRandom()) { 244 Dummy *_Nonnull varWithInitializer = p; // no-warning 245 246 Dummy *_Nonnull var1WithInitializer = p, // no-warning 247 *_Nonnull var2WithInitializer = p; // no-warning 248 } 249 250 if (getRandom()) { 251 Dummy *_Nonnull varWithoutInitializer; 252 varWithoutInitializer = p; // no-warning 253 } 254 255 return p; 256} 257