Available Checkers
The analyzer performs checks that are categorized into families or "checkers". The default set of checkers covers a variety of checks targeted at finding security and API usage bugs, dead code, and other logic errors. See the Default Checkers list below. In addition to these, the analyzer contains a number of Experimental (Alpha) Checkers.Writeups with examples of some of the bugs that the analyzer finds
- Bug Finding With Clang: 5 Resources To Get You Started
- Finding Memory Leaks With The LLVM/Clang Static Analyzer
- Under the Microscope - The Clang Static Analyzer
- Mike Ash - Using the Clang Static Analyzer
Default Checkers
- Core Checkers model core language features and perform general-purpose checks such as division by zero, null pointer dereference, usage of uninitialized values, etc.
- C++ Checkers perform C++-specific checks
- Dead Code Checkers check for unused code
- Nullability Checkers
- Optin Checkers
- OS X Checkers perform Objective-C-specific checks and check the use of Apple's SDKs (OS X and iOS)
- Security Checkers check for insecure API usage and perform checks based on the CERT Secure Coding Standards
- Unix Checkers check the use of Unix and POSIX APIs
Core Checkers
Name, Description | Example |
core.CallAndMessage
(C, C++, ObjC)
Check for logical errors for function calls and Objective-C message expressions
(e.g., uninitialized arguments, null function pointers). |
// C struct S { int x; }; void f(struct S s); void test() { struct S s; f(s); // warn: passed-by-value arg contain uninitialized data } // C void test() { void (*foo)(void); foo(); // warn: function pointer is uninitialized } // C void test() { void (*foo)(void); foo = 0; foo(); // warn: function pointer is null } // C++ class C { public: void f(); }; void test() { C *pc; pc->f(); // warn: object pointer is uninitialized } // C++ class C { public: void f(); }; void test() { C *pc = 0; pc->f(); // warn: object pointer is null } // Objective-C @interface MyClass : NSObject @property (readwrite,assign) id x; - (long double)longDoubleM; @end void test() { MyClass *obj1; long double ld1 = [obj1 longDoubleM]; // warn: receiver is uninitialized } // Objective-C @interface MyClass : NSObject @property (readwrite,assign) id x; - (long double)longDoubleM; @end void test() { MyClass *obj1; id i = obj1.x; // warn: uninitialized object pointer } // Objective-C @interface Subscriptable : NSObject - (id)objectAtIndexedSubscript:(unsigned int)index; @end @interface MyClass : Subscriptable @property (readwrite,assign) id x; - (long double)longDoubleM; @end void test() { MyClass *obj1; id i = obj1[0]; // warn: uninitialized object pointer } |
core.DivideZero
(C, C++, ObjC)
Check for division by zero. |
void test(int z) { if (z == 0) int x = 1 / z; // warn } void test() { int x = 1; int y = x % 0; // warn } |
core.NonNullParamChecker
(C, C++, ObjC)
Check for null pointers passed as arguments to a function whose arguments are
marked with the nonnull attribute. |
int f(int *p) __attribute__((nonnull)); void test(int *p) { if (!p) f(p); // warn } |
core.NullDereference
(C, C++, ObjC)
Check for dereferences of null pointers. |
// C void test(int *p) { if (p) return; int x = p[0]; // warn } // C void test(int *p) { if (!p) *p = 0; // warn } // C++ class C { public: int x; }; void test() { C *pc = 0; int k = pc->x; // warn } // Objective-C @interface MyClass { @public int x; } @end void test() { MyClass *obj = 0; obj->x = 1; // warn } |
core.StackAddressEscape
(C)
Check that addresses of stack memory do not escape the function. |
char const *p; void test() { char const str[] = "string"; p = str; // warn } void* test() { return __builtin_alloca(12); // warn } void test() { static int *x; int y; x = &y; // warn } |
core.UndefinedBinaryOperatorResult
(C)
Check for undefined results of binary operators. |
void test() { int x; int y = x + 1; // warn: left operand is garbage } |
core.VLASize
(C)
Check for declarations of VLA of undefined or zero size. |
void test() { int x; int vla1[x]; // warn: garbage as size } void test() { int x = 0; int vla2[x]; // warn: zero size } |
core.uninitialized.ArraySubscript
(C)
Check for uninitialized values used as array subscripts. |
void test() { int i, a[10]; int x = a[i]; // warn: array subscript is undefined } |
core.uninitialized.Assign
(C)
Check for assigning uninitialized values. |
void test() { int x; x |= 1; // warn: left expression is uninitialized } |
core.uninitialized.Branch
(C)
Check for uninitialized values used as branch conditions. |
void test() { int x; if (x) // warn return; } |
core.uninitialized.CapturedBlockVariable
(C)
Check for blocks that capture uninitialized values. |
void test() { int x; ^{ int y = x; }(); // warn } |
core.uninitialized.UndefReturn
(C)
Check for uninitialized values being returned to the caller. |
int test() { int x; return x; // warn } |
C++ Checkers
Name, Description | Example |
cplusplus.NewDelete
(C++)
Check for double-free, use-after-free and offset problems involving C++
delete . |
void f(int *p); void testUseMiddleArgAfterDelete(int *p) { delete p; f(p); // warn: use after free } class SomeClass { public: void f(); }; void test() { SomeClass *c = new SomeClass; delete c; c->f(); // warn: use after free } void test() { int *p = (int *)__builtin_alloca(sizeof(int)); delete p; // warn: deleting memory allocated by alloca } void test() { int *p = new int; delete p; delete p; // warn: attempt to free released } void test() { int i; delete &i; // warn: delete address of local } void test() { int *p = new int[1]; delete[] (++p); // warn: argument to 'delete[]' is offset by 4 bytes // from the start of memory allocated by 'new[]' } |
cplusplus.NewDeleteLeaks
(C++)
Check for memory leaks. Traces memory managed by new /
delete . |
void test() { int *p = new int; } // warn |
Dead Code Checkers
Name, Description | Example |
deadcode.DeadStores
(C)
Check for values stored to variables that are never read afterwards. |
void test() { int x; x = 1; // warn } |
Nullability Checkers
Name, Description | Example |
nullability.NullPassedToNonnull
(ObjC)
Warns when a null pointer is passed to a pointer which has a
_Nonnull type. |
if (name != nil) return; // Warning: nil passed to a callee that requires a non-null 1st parameter NSString *greeting = [@"Hello " stringByAppendingString:name]; |
nullability.NullReturnedFromNonnull
(ObjC)
Warns when a null pointer is returned from a function that has
_Nonnull return type. |
- (nonnull id)firstChild { id result = nil; if ([_children count] > 0) result = _children[0]; // Warning: nil returned from a method that is expected // to return a non-null value return result; } |
nullability.NullableDereferenced
(ObjC)
Warns when a nullable pointer is dereferenced. |
struct LinkedList { int data; struct LinkedList *next; }; struct LinkedList * _Nullable getNext(struct LinkedList *l); void updateNextData(struct LinkedList *list, int newData) { struct LinkedList *next = getNext(list); // Warning: Nullable pointer is dereferenced next->data = 7; } |
nullability.NullablePassedToNonnull
(ObjC)
Warns when a nullable pointer is passed to a pointer which has a _Nonnull type. |
typedef struct Dummy { int val; } Dummy; Dummy *_Nullable returnsNullable(); void takesNonnull(Dummy *_Nonnull); void test() { Dummy *p = returnsNullable(); takesNonnull(p); // warn } |
Optin Checkers
Name, Description | Example |
optin.mpi.MPI-Checker
(C)
Checks MPI code |
void test() { double buf = 0; MPI_Request sendReq1; MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &sendReq1); } // warn: request 'sendReq1' has no matching wait. void test() { double buf = 0; MPI_Request sendReq; MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); MPI_Irecv(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // warn MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // warn MPI_Wait(&sendReq, MPI_STATUS_IGNORE); } void missingNonBlocking() { int rank = 0; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Request sendReq1[10][10][10]; MPI_Wait(&sendReq1[1][7][9], MPI_STATUS_IGNORE); // warn } |
optin.osx.cocoa.localizability.EmptyLocalizationContextChecker
(ObjC)
Check that NSLocalizedString macros include a comment for context. |
- (void)test { NSString *string = NSLocalizedString(@"LocalizedString", nil); // warn NSString *string2 = NSLocalizedString(@"LocalizedString", @" "); // warn NSString *string3 = NSLocalizedStringWithDefaultValue( @"LocalizedString", nil, [[NSBundle alloc] init], nil,@""); // warn } |
optin.osx.cocoa.localizability.NonLocalizedStringChecker
(ObjC)
Warns about uses of non-localized NSStrings passed to UI methods
expecting localized NSStrings |
NSString *alarmText = NSLocalizedString(@"Enabled", @"Indicates alarm is turned on"); if (!isEnabled) { alarmText = @"Disabled"; } UILabel *alarmStateLabel = [[UILabel alloc] init]; // Warning: User-facing text should use localized string macro [alarmStateLabel setText:alarmText]; |
OS X Checkers
Name, Description | Example |
osx.API
(C)
Check for proper uses of various Apple APIs:
dispatch_once |
void test() { dispatch_once_t pred = 0; dispatch_once(&pred, ^(){}); // warn: dispatch_once uses local } |
osx.NumberObjectConversion
(C, C++, ObjC)
Check for erroneous conversions of objects representing numbers
into numbers |
NSNumber *photoCount = [albumDescriptor objectForKey:@"PhotoCount"]; // Warning: Comparing a pointer value of type 'NSNumber *' // to a scalar integer value if (photoCount > 0) { [self displayPhotos]; } |
osx.SecKeychainAPI
(C)
Check for improper uses of the Security framework's Keychain APIs:
SecKeychainItemCopyContent SecKeychainFindGenericPassword SecKeychainFindInternetPassword SecKeychainItemFreeContent SecKeychainItemCopyAttributesAndData SecKeychainItemFreeAttributesAndData |
void test() { unsigned int *ptr = 0; UInt32 length; SecKeychainItemFreeContent(ptr, &length); // warn: trying to free data which has not been allocated } void test() { unsigned int *ptr = 0; UInt32 *length = 0; void *outData; OSStatus st = SecKeychainItemCopyContent(2, ptr, ptr, length, outData); // warn: data is not released } void test() { unsigned int *ptr = 0; UInt32 *length = 0; void *outData; OSStatus st = SecKeychainItemCopyContent(2, ptr, ptr, length, &outData); SecKeychainItemFreeContent(ptr, outData); // warn: only call free if a non-NULL buffer was returned } void test() { unsigned int *ptr = 0; UInt32 *length = 0; void *outData; OSStatus st = SecKeychainItemCopyContent(2, ptr, ptr, length, &outData); st = SecKeychainItemCopyContent(2, ptr, ptr, length, &outData); // warn: release data before another call to the allocator if (st == noErr) SecKeychainItemFreeContent(ptr, outData); } void test() { SecKeychainItemRef itemRef = 0; SecKeychainAttributeInfo *info = 0; SecItemClass *itemClass = 0; SecKeychainAttributeList *attrList = 0; UInt32 *length = 0; void *outData = 0; OSStatus st = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, &attrList, length, &outData); SecKeychainItemFreeContent(attrList, outData); // warn: deallocator doesn't match the allocator } |
osx.cocoa.AtSync
(ObjC)
Check for nil pointers used as mutexes for @synchronized . |
void test(id x) { if (!x) @synchronized(x) {} // warn: nil value used as mutex } void test() { id y; @synchronized(y) {} // warn: uninitialized value used as mutex } |
osx.cocoa.ClassRelease
(ObjC)
Check for sending retain , release , or
autorelease directly to a class. |
@interface MyClass : NSObject @end void test(void) { [MyClass release]; // warn } |
osx.cocoa.Dealloc
(ObjC)
Warn about Objective-C classes that lack a correct implementation
of -dealloc .
|
@interface MyObject : NSObject { id _myproperty; } @end @implementation MyObject // warn: lacks 'dealloc' @end @interface MyObject : NSObject {} @property(assign) id myproperty; @end @implementation MyObject // warn: does not send 'dealloc' to super - (void)dealloc { self.myproperty = 0; } @end @interface MyObject : NSObject { id _myproperty; } @property(retain) id myproperty; @end @implementation MyObject @synthesize myproperty = _myproperty; // warn: var was retained but wasn't released - (void)dealloc { [super dealloc]; } @end @interface MyObject : NSObject { id _myproperty; } @property(assign) id myproperty; @end @implementation MyObject @synthesize myproperty = _myproperty; // warn: var wasn't retained but was released - (void)dealloc { [_myproperty release]; [super dealloc]; } @end |
osx.cocoa.IncompatibleMethodTypes
(ObjC)
Check for an incompatible type signature when overriding an Objective-C method. |
@interface MyClass1 : NSObject - (int)foo; @end @implementation MyClass1 - (int)foo { return 1; } @end @interface MyClass2 : MyClass1 - (float)foo; @end @implementation MyClass2 - (float)foo { return 1.0; } // warn @end |
alpha.osx.cocoa.MissingSuperCall
(ObjC)
Warn about Objective-C methods that lack a necessary call to super. (Note: The
compiler now has a warning for methods annotated with objc_requires_super
attribute. The checker exists to check methods in the Cocoa frameworks
that haven't yet adopted this attribute.) |
@interface Test : UIViewController @end @implementation test - (void)viewDidLoad {} // warn @end |
osx.cocoa.NSAutoreleasePool
(ObjC)
Warn for suboptimal uses of NSAutoreleasePool in Objective-C
GC mode ( -fobjc-gc compiler option). |
void test() { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [pool release]; // warn } |
osx.cocoa.NSError
(ObjC)
Check usage of NSError** parameters. |
@interface A : NSObject - (void)foo:(NSError **)error; @end @implementation A - (void)foo:(NSError **)error { // warn: method accepting NSError** should have a non-void // return value } @end @interface A : NSObject - (BOOL)foo:(NSError **)error; @end @implementation A - (BOOL)foo:(NSError **)error { *error = 0; // warn: potential null dereference return 0; } @end |
osx.cocoa.NilArg
(ObjC)
Check for prohibited nil arguments in specific Objective-C method calls:
- caseInsensitiveCompare: - compare: - compare:options: - compare:options:range: - compare:options:range:locale: - componentsSeparatedByCharactersInSet: - initWithFormat: |
NSComparisonResult test(NSString *s) { NSString *aString = nil; return [s caseInsensitiveCompare:aString]; // warn: argument to 'NSString' method // 'caseInsensitiveCompare:' cannot be nil } |
osx.cocoa.ObjCGenerics
(ObjC)
Check for type errors when using Objective-C generics |
NSMutableArray |
osx.cocoa.RetainCount
(ObjC)
Check for leaks and violations of the Cocoa Memory Management rules. |
void test() { NSString *s = [[NSString alloc] init]; // warn } CFStringRef test(char *bytes) { return CFStringCreateWithCStringNoCopy( 0, bytes, NSNEXTSTEPStringEncoding, 0); // warn } |
osx.cocoa.SelfInit
(ObjC)
Check that self is properly initialized inside an initializer
method. |
@interface MyObj : NSObject { id x; } - (id)init; @end @implementation MyObj - (id)init { [super init]; x = 0; // warn: instance variable used while 'self' is not // initialized return 0; } @end @interface MyObj : NSObject - (id)init; @end @implementation MyObj - (id)init { [super init]; return self; // warn: returning uninitialized 'self' } @end |
osx.cocoa.SuperDealloc
(ObjC)
Warn about improper use of '[super dealloc]' in Objective-C |
@interface SuperDeallocThenReleaseIvarClass : NSObject { NSObject *_ivar; } @end @implementation SuperDeallocThenReleaseIvarClass - (void)dealloc { [super dealloc]; [_ivar release]; // warn } @end |
osx.cocoa.UnusedIvars
(ObjC)
Warn about private ivars that are never used. |
@interface MyObj : NSObject { @private id x; // warn } @end @implementation MyObj @end |
osx.cocoa.VariadicMethodTypes
(ObjC)
Check for passing non-Objective-C types to variadic collection initialization
methods that expect only Objective-C types. |
void test() { [NSSet setWithObjects:@"Foo", "Bar", nil]; // warn: argument should be an ObjC pointer type, not 'char *' } |
osx.coreFoundation.CFError
(C)
Check usage of CFErrorRef* parameters. |
void test(CFErrorRef *error) { // warn: function accepting CFErrorRef* should have a // non-void return } int foo(CFErrorRef *error) { *error = 0; // warn: potential null dereference return 0; } |
osx.coreFoundation.CFNumber
(C)
Check for improper uses of CFNumberCreate . |
CFNumberRef test(unsigned char x) { return CFNumberCreate(0, kCFNumberSInt16Type, &x); // warn: 8 bit integer is used to initialize a 16 bit integer } |
osx.coreFoundation.CFRetainRelease
(C)
Check for null arguments to CFRetain , CFRelease ,
CFMakeCollectable . |
void test(CFTypeRef p) { if (!p) CFRetain(p); // warn } void test(int x, CFTypeRef p) { if (p) return; CFRelease(p); // warn } |
osx.coreFoundation.containers.OutOfBounds
(C)
Checks for index out-of-bounds when using CFArray API. |
void test() { CFArrayRef A = CFArrayCreate(0, 0, 0, &kCFTypeArrayCallBacks); CFArrayGetValueAtIndex(A, 0); // warn } |
osx.coreFoundation.containers.PointerSizedValues
(C)
Warns if CFArray , CFDictionary , CFSet are
created with non-pointer-size values. |
void test() { int x[] = { 1 }; CFArrayRef A = CFArrayCreate(0, (const void **)x, 1, &kCFTypeArrayCallBacks); // warn } |
Security Checkers
Name, Description | Example |
security.FloatLoopCounter
(C)
Warn on using a floating point value as a loop counter (CERT: FLP30-C,
FLP30-CPP). |
void test() { for (float x = 0.1f; x <= 1.0f; x += 0.1f) {} // warn } |
security.insecureAPI.UncheckedReturn
(C)
Warn on uses of functions whose return values must be always checked:
setuid setgid seteuid setegid setreuid setregid |
void test() { setuid(1); // warn } |
security.insecureAPI.bcmp
(C)
Warn on uses of the bcmp function. |
void test() { bcmp(ptr0, ptr1, n); // warn } |
security.insecureAPI.bcopy
(C)
Warn on uses of the bcopy function. |
void test() { bcopy(src, dst, n); // warn } |
security.insecureAPI.bzero
(C)
Warn on uses of the bzero function. |
void test() { bzero(ptr, n); // warn } |
security.insecureAPI.getpw
(C)
Warn on uses of the getpw function. |
void test() { char buff[1024]; getpw(2, buff); // warn } |
security.insecureAPI.gets
(C)
Warn on uses of the gets function. |
void test() { char buff[1024]; gets(buff); // warn } |
security.insecureAPI.mkstemp
(C)
Warn when mktemp , mkstemp , mkstemps or
mkdtemp is passed fewer than 6
X's in the format string. |
void test() { mkstemp("XX"); // warn } |
security.insecureAPI.mktemp
(C)
Warn on uses of the mktemp function. |
void test() { char *x = mktemp("/tmp/zxcv"); // warn: insecure, use mkstemp } |
security.insecureAPI.rand
(C)
Warn on uses of inferior random number generating functions (only if arc4random
function is available):
drand48 erand48 jrand48 lcong48 lrand48 mrand48 nrand48 random rand_r |
void test() { random(); // warn } |
security.insecureAPI.strcpy
(C)
Warn on uses of the strcpy and strcat functions. |
void test() { char x[4]; char *y = "abcd"; strcpy(x, y); // warn } |
security.insecureAPI.vfork
(C)
Warn on uses of the vfork function. |
void test() { vfork(); // warn } |
Unix Checkers
Name, Description | Example |
unix.API
(C)
Check calls to various UNIX/POSIX functions:
open pthread_once calloc malloc realloc alloca // Currently the check is performed for apple targets only. void test(const char *path) { int fd = open(path, O_CREAT); // warn: call to 'open' requires a third argument when the // 'O_CREAT' flag is set } void f(); void test() { pthread_once_t pred = {0x30B1BCBA, {0}}; pthread_once(&pred, f); // warn: call to 'pthread_once' uses the local variable } void test() { void *p = malloc(0); // warn: allocation size of 0 bytes } void test() { void *p = calloc(0, 42); // warn: allocation size of 0 bytes } void test() { void *p = malloc(1); p = realloc(p, 0); // warn: allocation size of 0 bytes } void test() { void *p = alloca(0); // warn: allocation size of 0 bytes } void test() { void *p = valloc(0); // warn: allocation size of 0 bytes } | |
unix.Malloc
(C)
Check for memory leaks, double free, and use-after-free and offset problems
involving malloc . |
void test() { int *p = malloc(1); free(p); free(p); // warn: attempt to free released memory } void test() { int *p = malloc(sizeof(int)); free(p); *p = 1; // warn: use after free } void test() { int *p = malloc(1); if (p) return; // warn: memory is never released } void test() { int a[] = { 1 }; free(a); // warn: argument is not allocated by malloc } void test() { int *p = malloc(sizeof(char)); p = p - 1; free(p); // warn: argument to free() is offset by -4 bytes } |
unix.MallocSizeof
(C)
Check for dubious malloc , calloc or
realloc arguments involving sizeof . |
void test() { long *p = malloc(sizeof(short)); // warn: result is converted to 'long *', which is // incompatible with operand type 'short' free(p); } |
unix.MismatchedDeallocator
(C, C++, ObjC)
Check for mismatched deallocators (e.g. passing a pointer allocating
with new to free() ). |
// C, C++ void test() { int *p = (int *)malloc(sizeof(int)); delete p; // warn } // C, C++ void __attribute((ownership_returns(malloc))) *user_malloc(size_t); void test() { int *p = (int *)user_malloc(sizeof(int)); delete p; // warn } // C, C++ void test() { int *p = new int; free(p); // warn } // C, C++ void test() { int *p = new int[1]; realloc(p, sizeof(long)); // warn } // C, C++ template <typename T> struct SimpleSmartPointer { T *ptr; explicit SimpleSmartPointer(T *p = 0) : ptr(p) {} ~SimpleSmartPointer() { delete ptr; // warn } }; void test() { SimpleSmartPointer<int> a((int *)malloc(4)); } // C++ void test() { int *p = (int *)operator new(0); delete[] p; // warn } // Objective-C, C++ void test(NSUInteger dataLength) { int *p = new int; NSData *d = [NSData dataWithBytesNoCopy:p length:sizeof(int) freeWhenDone:1]; // warn +dataWithBytesNoCopy:length:freeWhenDone: cannot take // ownership of memory allocated by 'new' } |
unix.Vfork
(C)
Check for proper usage of vfork |
int test(int x) { pid_t pid = vfork(); // warn if (pid != 0) return 0; switch (x) { case 0: pid = 1; execl("", "", 0); _exit(1); break; case 1: x = 0; // warn: this assignment is prohibited break; case 2: foo(); // warn: this function call is prohibited break; default: return 0; // warn: return is prohibited } while(1); } |
unix.cstring.BadSizeArg
(C)
Check the size argument passed to strncat for common erroneous
patterns. Use -Wno-strncat-size compiler option to mute other
strncat -related compiler warnings.
|
void test() { char dest[3]; strncat(dest, "***", sizeof(dest)); // warn: potential buffer overflow } |
unix.cstring.NullArg
(C)
Check for null pointers being passed as arguments to C string functions:
strlen strnlen strcpy strncpy strcat strncat strcmp strncmp strcasecmp strncasecmp |
int test() { return strlen(0); // warn } |