1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
// RUN: %clang_analyze_cc1 -fblocks -fobjc-arc -verify %s -Wno-objc-root-class \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=alpha.core.StackAddressAsyncEscape \
// RUN: -analyzer-checker=nullability \
// RUN: -analyzer-checker=osx
#include "Inputs/system-header-simulator-for-nullability.h"
#include "os_object_base.h"
struct OSIterator : public OSObject {
static const OSMetaClass * const metaClass;
};
@interface TestObject : NSObject
- (int *_Nonnull)returnsNonnull;
- (int *_Nullable)returnsNullable;
- (int *)returnsUnspecified;
- (void)takesNonnull:(int *_Nonnull)p;
- (void)takesNullable:(int *_Nullable)p;
- (void)takesUnspecified:(int *)p;
@property(readonly, strong) NSString *stuff;
@end
TestObject * getUnspecifiedTestObject();
TestObject *_Nonnull getNonnullTestObject();
TestObject *_Nullable getNullableTestObject();
int getRandom();
typedef struct Dummy { int val; } Dummy;
void takesNullable(Dummy *_Nullable);
void takesNonnull(Dummy *_Nonnull);
void takesUnspecified(Dummy *);
Dummy *_Nullable returnsNullable();
Dummy *_Nonnull returnsNonnull();
Dummy *returnsUnspecified();
int *_Nullable returnsNullableInt();
template <typename T> T *eraseNullab(T *p) { return p; }
void takesAttrNonnull(Dummy *p) __attribute((nonnull(1)));
void testBasicRules() {
// FIXME: None of these should be tied to a modeling checker.
Dummy *p = returnsNullable();
int *ptr = returnsNullableInt();
// Make every dereference a different path to avoid sinks after errors.
switch (getRandom()) {
case 0: {
Dummy &r = *p; // expected-warning {{Nullable pointer is dereferenced [nullability.NullableDereferenced]}}
} break;
case 1: {
int b = p->val; // expected-warning {{Nullable pointer is dereferenced [nullability.NullableDereferenced]}}
} break;
case 2: {
int stuff = *ptr; // expected-warning {{Nullable pointer is dereferenced [nullability.NullableDereferenced]}}
} break;
case 3:
takesNonnull(p); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter [nullability.NullablePassedToNonnull]}}
break;
case 4: {
Dummy d;
takesNullable(&d);
Dummy dd(d);
break;
}
case 5:
takesAttrNonnull(p); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null [nullability.NullableDereferenced]}}
break;
default: { Dummy d = *p; } break; // expected-warning {{Nullable pointer is dereferenced [nullability.NullableDereferenced]}}
}
if (p) {
takesNonnull(p);
if (getRandom()) {
Dummy &r = *p;
} else {
int b = p->val;
}
}
Dummy *q = 0;
if (getRandom()) {
takesNullable(q);
// FIXME: This shouldn't be tied to a modeling checker.
takesNonnull(q); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter [nullability.NullPassedToNonnull]}}
}
Dummy a;
Dummy *_Nonnull nonnull = &a;
// FIXME: This shouldn't be tied to a modeling checker.
nonnull = q; // expected-warning {{Null assigned to a pointer which is expected to have non-null value [nullability.NullPassedToNonnull]}}
q = &a;
takesNullable(q);
takesNonnull(q);
}
typedef int NSInteger;
typedef struct _NSZone NSZone;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
@class NSDictionary;
@interface NSError : NSObject <NSCopying, NSCoding> {}
+ (id)errorWithDomain:(NSString *)domain code:(NSInteger)code userInfo:(NSDictionary *)dict;
@end
struct __CFError {};
typedef struct __CFError* CFErrorRef;
void foo(CFErrorRef* error) { // expected-warning{{Function accepting CFErrorRef* should have a non-void return value to indicate whether or not an error occurred [osx.coreFoundation.CFError]}}
// FIXME: This shouldn't be tied to a modeling checker.
*error = 0; // expected-warning {{Potential null dereference. According to coding standards documented in CoreFoundation/CFError.h the parameter may be null [osx.coreFoundation.CFError]}}
}
@interface A
- (void)myMethodWhichMayFail:(NSError **)error;
@end
@implementation A
- (void)myMethodWhichMayFail:(NSError **)error { // expected-warning {{Method accepting NSError** should have a non-void return value to indicate whether or not an error occurred [osx.cocoa.NSError]}}
*error = [NSError errorWithDomain:@"domain" code:1 userInfo:0]; // expected-warning {{Potential null dereference. According to coding standards in 'Creating and Returning NSError Objects' the parameter may be null [osx.cocoa.NSError]}}
}
@end
bool write_into_out_param_on_success(OS_RETURNS_RETAINED OSObject **obj);
void use_out_param_leak() {
OSObject *obj;
// FIXME: This shouldn't be tied to a modeling checker.
write_into_out_param_on_success(&obj); // expected-warning{{Potential leak of an object stored into 'obj' [osx.cocoa.RetainCount]}}
}
typedef struct dispatch_queue_s *dispatch_queue_t;
typedef void (^dispatch_block_t)(void);
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
typedef long dispatch_once_t;
void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
typedef long dispatch_time_t;
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);
extern dispatch_queue_t queue;
extern dispatch_once_t *predicate;
extern dispatch_time_t when;
dispatch_block_t get_leaking_block() {
int leaked_x = 791;
int *p = &leaked_x;
return ^void(void) {
*p = 1;
};
// expected-warning@-3 {{Address of stack memory associated with local variable 'leaked_x' \
is captured by a returned block [core.StackAddressEscape]}}
}
void test_returned_from_func_block_async() {
dispatch_async(queue, get_leaking_block());
// expected-warning@-1 {{Address of stack memory associated with local variable 'leaked_x' \
is captured by an asynchronously-executed block [alpha.core.StackAddressAsyncEscape]}}
}
|