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) co
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 |
cplusplus.UninitializedObject
(C++)
This checker reports uninitialized fields in objects created after a constructor
call. It doesn't only find direct uninitialized fields, but rather makes a deep
inspection of the object, analyzing all of it's fields subfields. The checker regards inherited fields as direct fields, so one will recieve warnings for uninitialized inherited data members as well. It has several options:
|
// With Pedantic and CheckPointeeInitialization set to true struct A { struct B { int x; // note: uninitialized field 'this->b.x' // note: uninitialized field 'this->bptr->x' int y; // note: uninitialized field 'this->b.y' // note: uninitialized field 'this->bptr->y' }; int *iptr; // note: uninitialized pointer 'this->iptr' B b; B *bptr; char *cptr; // note: uninitialized pointee 'this->cptr' A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {} }; void f() { A::B b; char c; A a(&b, &c); // warning: 6 uninitialized fields // after the constructor call } // With Pedantic set to false and // CheckPointeeInitialization set to true // (every field is uninitialized) struct A { struct B { int x; int y; }; int *iptr; B b; B *bptr; char *cptr; A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {} }; void f() { A::B b; char c; A a(&b, &c); // no warning } // With Pedantic and CheckPointeeInitialization set to false // (pointees are regarded as initialized) struct A { struct B { int x; // note: uninitialized field 'this->b.x' int y; // note: uninitialized field 'this->b.y' }; int *iptr; // note: uninitialized pointer 'this->iptr' B b; B *bptr; char *cptr; A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {} }; void f() { A::B b; char c; A a(&b, &c); // warning: 3 uninitialized fields // after the constructor call } |
optin.cplusplus.VirtualCall
(C++)
Check virtual member function calls during construction or
destruction. |
class A { public: A() { f(); // warn } virtual void f(); }; class A { public: ~A() { this->f(); // warn } virtual void f(); }; |
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 |
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
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 } |