Alpha Checkers
+Experimental checkers in addition to the Default Checkers. +-
+
- Core Alpha Checkers +
- C++ Alpha Checkers +
- Dead Code Alpha Checkers +
- OS X Alpha Checkers +
- Security Alpha Checkers +
- Unix Alpha Checkers +
Core Alpha Checkers
+Name, Description | Example |
+alpha.core.BoolAssignment
+(ObjC)
+Warn about assigning non-{0,1} values to boolean variables. |
+
+ +void test() { + BOOL b = -1; // warn +} + |
+alpha.core.CastSize
+(C)
+Check when casting a malloc'ed type T, whether the size is a multiple of the
+size of T (Works only with unix.Malloc
+or alpha.unix.MallocWithAnnotations
+checks enabled). |
+
+ +void test() { + int *x = (int *)malloc(11); // warn +} + |
+alpha.core.CastToStruct
+(C, C++)
+Check for cast from non-struct pointer to struct pointer. |
+
+ +// C +struct s {}; + +void test(int *p) { + struct s *ps = (struct s *) p; // warn +} + +// C++ +class c {}; + +void test(int *p) { + c *pc = (c *) p; // warn +} + |
+alpha.core.FixedAddr
+(C)
+Check for assignment of a fixed address to a pointer. |
+
+ +void test() { + int *p; + p = (int *) 0x10000; // warn +} + |
+alpha.core.IdenticalExpr
+(C, C++)
+Warn about unintended use of identical expressions in operators. |
+
+ +// C +void test() { + int a = 5; + int b = a | 4 | a; // warn: identical expr on both sides +} + +// C++ +bool f(void); + +void test(bool b) { + int i = 10; + if (f()) { // warn: true and false branches are identical + do { + i--; + } while (f()); + } else { + do { + i--; + } while (f()); + } +} + |
+alpha.core.PointerArithm
+(C)
+Check for pointer arithmetic on locations other than array elements. |
+
+ +void test() { + int x; + int *p; + p = &x + 1; // warn +} + |
+alpha.core.PointerSub
+(C)
+Check for pointer subtractions on two pointers pointing to different memory
+chunks. |
+
+ +void test() { + int x, y; + int d = &y - &x; // warn +} + |
+alpha.core.SizeofPtr
+(C)
+Warn about unintended use of sizeof() on pointer
+expressions. |
+
+ +struct s {}; + +int test(struct s *p) { + return sizeof(p); + // warn: sizeof(ptr) can produce an unexpected result +} + |
C++ Alpha Checkers
+Name, Description | Example |
+alpha.cplusplus.NewDeleteLeaks
+(C++)
+Check for memory leaks. Traces memory managed by new /
+delete . |
+
+ +void test() { + int *p = new int; +} // warn + |
+alpha.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(); +}; + |
Dead Code Alpha Checkers
+Name, Description | Example |
+alpha.deadcode.UnreachableCode
+(C, C++, ObjC)
+Check unreachable code. |
+
+ +// C +int test() { + int x = 1; + while(x); + return x; // warn +} + +// C++ +void test() { + int a = 2; + + while (a > 1) + a--; + + if (a > 1) + a++; // warn +} + +// Objective-C +void test(id x) { + return; + [x retain]; // warn +} + |
OS X Alpha Checkers
+Name, Description | Example |
+alpha.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 + |
+alpha.osx.cocoa.DirectIvarAssignment
+(ObjC)
+Check that Objective C properties follow the following rule: the property
+should be set with the setter, not though a direct assignment. |
+
+ +@interface MyClass : NSObject {} +@property (readonly) id A; +- (void) foo; +@end + +@implementation MyClass +- (void) foo { + _A = 0; // warn +} +@end + |
+alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions
+(ObjC)
+Check for direct assignments to instance variables in the methods annotated
+with objc_no_direct_instance_variable_assignment . |
+
+ +@interface MyClass : NSObject {} +@property (readonly) id A; +- (void) fAnnotated __attribute__(( + annotate("objc_no_direct_instance_variable_assignment"))); +- (void) fNotAnnotated; +@end + +@implementation MyClass +- (void) fAnnotated { + _A = 0; // warn +} +- (void) fNotAnnotated { + _A = 0; // no warn +} +@end + |
+alpha.osx.cocoa.InstanceVariableInvalidation
+(ObjC)
+Check that the invalidatable instance variables are invalidated in the methods
+annotated with objc_instance_variable_invalidator . |
+
+ +@protocol Invalidation <NSObject> +- (void) invalidate + __attribute__((annotate("objc_instance_variable_invalidator"))); +@end + +@interface InvalidationImpObj : NSObject <Invalidation> +@end + +@interface SubclassInvalidationImpObj : InvalidationImpObj { + InvalidationImpObj *var; +} +- (void)invalidate; +@end + +@implementation SubclassInvalidationImpObj +- (void) invalidate {} +@end +// warn: var needs to be invalidated or set to nil + |
+alpha.osx.cocoa.MissingInvalidationMethod
+(ObjC)
+Check that the invalidation methods are present in classes that contain
+invalidatable instance variables. |
+
+ +@protocol Invalidation <NSObject> +- (void)invalidate + __attribute__((annotate("objc_instance_variable_invalidator"))); +@end + +@interface NeedInvalidation : NSObject <Invalidation> +@end + +@interface MissingInvalidationMethodDecl : NSObject { + NeedInvalidation *Var; // warn +} +@end + +@implementation MissingInvalidationMethodDecl +@end + |
Security Alpha Checkers
+Name, Description | Example |
+alpha.security.ArrayBound
+(C)
+Warn about buffer overflows (older checker). |
+
+ +void test() { + char *s = ""; + char c = s[1]; // warn +} + +struct seven_words { + int c[7]; +}; + +void test() { + struct seven_words a, *p; + p = &a; + p[0] = a; + p[1] = a; + p[2] = a; // warn +} + +// note: requires unix.Malloc or +// alpha.unix.MallocWithAnnotations checks enabled. +void test() { + int *p = malloc(12); + p[3] = 4; // warn +} + +void test() { + char a[2]; + int *b = (int*)a; + b[1] = 3; // warn +} + |
+alpha.security.ArrayBoundV2
+(C)
+Warn about buffer overflows (newer checker). |
+
+ +void test() { + char *s = ""; + char c = s[1]; // warn +} + +void test() { + int buf[100]; + int *p = buf; + p = p + 99; + p[1] = 1; // warn +} + +// note: compiler has internal check for this. +// Use -Wno-array-bounds to suppress compiler warning. +void test() { + int buf[100][100]; + buf[0][-1] = 1; // warn +} + +// note: requires alpha.security.taint check turned on. +void test() { + char s[] = "abc"; + int x = getchar(); + char c = s[x]; // warn: index is tainted +} + |
+alpha.security.MallocOverflow
+(C)
+Check for overflows in the arguments to malloc() . |
+
+ +void test(int n) { + void *p = malloc(n * sizeof(int)); // warn +} + |
+alpha.security.ReturnPtrRange
+(C)
+Check for an out-of-bound pointer being returned to callers. |
+
+ +static int A[10]; + +int *test() { + int *p = A + 10; + return p; // warn +} + +int test(void) { + int x; + return x; // warn: undefined or garbage returned +} + |
+alpha.security.taint.TaintPropagation
+(C)
+Generate taint information used by other checkers. |
+
+ +void test() { + char x = getchar(); // 'x' marked as tainted + system(&x); // warn: untrusted data is passed to a system call +} + +// note: compiler internally checks if the second param to +// sprintf is a string literal or not. +// Use -Wno-format-security to suppress compiler warning. +void test() { + char s[10], buf[10]; + fscanf(stdin, "%s", s); // 's' marked as tainted + + sprintf(buf, s); // warn: untrusted data as a format string +} + +void test() { + size_t ts; + scanf("%zd", &ts); // 'ts' marked as tainted + int *p = (int *)malloc(ts * sizeof(int)); + // warn: untrusted data as bufer size +} + |
Unix Alpha Checkers
+Name, Description | Example |
+alpha.unix.Chroot
+(C)
+Check improper use of chroot . |
+
+ +void f(); + +void test() { + chroot("/usr/local"); + f(); // warn: no call of chdir("/") immediately after chroot +} + |
+alpha.unix.MallocWithAnnotations
+(C)
+Check for memory leaks, double free, and use-after-free problems. Assumes that
+all user-defined functions which might free a pointer are annotated. |
+
+ +void __attribute((ownership_returns(malloc))) *my_malloc(size_t); + +void test() { + int *p = my_malloc(1); +} // warn: potential leak + +void __attribute((ownership_returns(malloc))) *my_malloc(size_t); +void __attribute((ownership_takes(malloc, 1))) my_free(void *); + +void test() { + int *p = my_malloc(1); + my_free(p); + my_free(p); // warn: attempt to free released +} + +void __attribute((ownership_returns(malloc))) *my_malloc(size_t); +void __attribute((ownership_holds(malloc, 1))) my_hold(void *); + +void test() { + int *p = my_malloc(1); + my_hold(p); + free(p); // warn: attempt to free non-owned memory +} + +void __attribute((ownership_takes(malloc, 1))) my_free(void *); + +void test() { + int *p = malloc(1); + my_free(p); + *p = 1; // warn: use after free +} + |
+alpha.unix.PthreadLock
+(C)
+Simple lock -> unlock checker; applies to:
+pthread_mutex_lock +pthread_rwlock_rdlock +pthread_rwlock_wrlock +lck_mtx_lock +lck_rw_lock_exclusive +lck_rw_lock_shared +pthread_mutex_trylock +pthread_rwlock_tryrdlock +pthread_rwlock_tryrwlock +lck_mtx_try_lock +lck_rw_try_lock_exclusive +lck_rw_try_lock_shared +pthread_mutex_unlock +pthread_rwlock_unlock +lck_mtx_unlock +lck_rw_done |
+
+ +pthread_mutex_t mtx; + +void test() { + pthread_mutex_lock(&mtx); + pthread_mutex_lock(&mtx); + // warn: this lock has already been acquired +} + +lck_mtx_t lck1, lck2; + +void test() { + lck_mtx_lock(&lck1); + lck_mtx_lock(&lck2); + lck_mtx_unlock(&lck1); + // warn: this was not the most recently acquired lock +} + +lck_mtx_t lck1, lck2; + +void test() { + if (lck_mtx_try_lock(&lck1) == 0) + return; + + lck_mtx_lock(&lck2); + lck_mtx_unlock(&lck1); + // warn: this was not the most recently acquired lock +} + |
+alpha.unix.SimpleStream
+(C)
+Check for misuses of stream APIs:
+fopen (demo checker, the subject of the demo
+(Slides
+,Video)
+by Anna Zaks and Jordan Rose presented at the
+2012 LLVM Developers' Meeting).+fclose |
+
+ +void test() { + FILE *F = fopen("myfile.txt", "w"); +} // warn: opened file is never closed + +void test() { + FILE *F = fopen("myfile.txt", "w"); + + if (F) + fclose(F); + + fclose(F); // warn: closing a previously closed file stream +} + |
+alpha.unix.Stream
+(C)
+Check stream handling functions: fopen +tmpfile +fclose +fread +fwrite +fseek +ftell +rewind +fgetpos +fsetpos +clearerr +feof +ferror +fileno |
+
+ +void test() { + FILE *p = fopen("foo", "r"); +} // warn: opened file is never closed + +void test() { + FILE *p = fopen("foo", "r"); + fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL + fclose(p); +} + +void test() { + FILE *p = fopen("foo", "r"); + + if (p) + fseek(p, 1, 3); + // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR + + fclose(p); +} + +void test() { + FILE *p = fopen("foo", "r"); + fclose(p); + fclose(p); // warn: already closed +} + +void test() { + FILE *p = tmpfile(); + ftell(p); // warn: stream pointer might be NULL + fclose(p); +} + |
+alpha.unix.cstring.BufferOverlap
+(C)
+Checks for overlap in two buffer arguments; applies to:
+memcpy +mempcpy |
+
+ +void test() { + int a[4] = {0}; + memcpy(a + 2, a + 1, 8); // warn +} + |
+alpha.unix.cstring.NotNullTerminated
+(C)
+Check for arguments which are not null-terminated strings; applies to:
+strlen +strnlen +strcpy +strncpy +strcat +strncat |
+
+ +void test() { + int y = strlen((char *)&test); // warn +} + |
+alpha.unix.cstring.OutOfBounds
+(C)
+Check for out-of-bounds access in string functions; applies to:
+strncopy +strncat |
+
+ +void test(char *y) { + char x[4]; + if (strlen(y) == 4) + strncpy(x, y, 5); // warn +} + |