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
+}
+ |