| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" |
| "http://www.w3.org/TR/html4/strict.dtd"> |
| <html> |
| <head> |
| <title>Alpha Checks</title> |
| <link type="text/css" rel="stylesheet" href="menu.css"> |
| <link type="text/css" rel="stylesheet" href="content.css"> |
| <script type="text/javascript" src="scripts/menu.js"></script> |
| <script type="text/javascript" src="scripts/expandcollapse.js"></script> |
| <style type="text/css"> |
| tr:first-child { width:20%; } |
| </style> |
| </head> |
| <body onload="initExpandCollapse()"> |
| |
| <div id="page"> |
| <!--#include virtual="menu.html.incl"--> |
| |
| <div id="content"> |
| <h1>Alpha Checkers</h1> |
| Experimental checkers in addition to the <a href = "available_checks.html"> |
| Default Checkers</a>. These are checkers with known issues or limitations that |
| keep them from being on by default. They are likely to have false positives. |
| Bug reports are welcome but will likely not be investigated for some time. |
| Patches welcome! |
| <ul> |
| <li><a href="#clone_alpha_checkers">Clone Alpha Checkers</a></li> |
| <li><a href="#core_alpha_checkers">Core Alpha Checkers</a></li> |
| <li><a href="#cplusplus_alpha_checkers">C++ Alpha Checkers</a></li> |
| <li><a href="#llvm_alpha_checkers">LLVM Checkers</a></li> |
| <li><a href="#valist_alpha_checkers">Variable Argument Alpha Checkers</a></li> |
| <li><a href="#deadcode_alpha_checkers">Dead Code Alpha Checkers</a></li> |
| <li><a href="#osx_alpha_checkers">OS X Alpha Checkers</a></li> |
| <li><a href="#security_alpha_checkers">Security Alpha Checkers</a></li> |
| <li><a href="#unix_alpha_checkers">Unix Alpha Checkers</a></li> |
| <li><a href="#nondeterminism_alpha_checkers">Non-determinism Alpha Checkers</a></li> |
| </ul> |
| |
| <!-- ============================= clone alpha ============================= --> |
| |
| <h3 id="clone_alpha_checkers">Clone Alpha Checkers</h3> |
| <table class="checkers"> |
| <colgroup><col class="namedescr"><col class="example"></colgroup> |
| <thead><tr><td>Name, Description</td><td>Example</td></tr></thead> |
| |
| <tbody> |
| <tr><td><a id="alpha.clone.CloneChecker"><div class="namedescr expandable"><span class="name"> |
| alpha.clone.CloneChecker</span><span class="lang"> |
| (C, C++, ObjC)</span><div class="descr"> |
| Reports similar pieces of code.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void log(); |
| |
| int max(int a, int b) { // warn |
| log(); |
| if (a > b) |
| return a; |
| return b; |
| } |
| |
| int maxClone(int x, int y) { // similar code here |
| log(); |
| if (x > y) |
| return x; |
| return y; |
| } |
| </pre></div></div></td></tr> |
| </tbody></table> |
| |
| <!-- ============================= core alpha ============================= --> |
| <h3 id="core_alpha_checkers">Core Alpha Checkers</h3> |
| <table class="checkers"> |
| <colgroup><col class="namedescr"><col class="example"></colgroup> |
| <thead><tr><td>Name, Description</td><td>Example</td></tr></thead> |
| |
| <tbody> |
| <tr><td><a id="alpha.core.BoolAssignment"><div class="namedescr expandable"><span class="name"> |
| alpha.core.BoolAssignment</span><span class="lang"> |
| (ObjC)</span><div class="descr"> |
| Warn about assigning non-{0,1} values to boolean variables.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test() { |
| BOOL b = -1; // warn |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.core.CallAndMessageUnInitRefArg"><div class="namedescr expandable"><span class="name"> |
| alpha.core.CallAndMessageUnInitRefArg</span><span class="lang"> |
| (C, C++)</span><div class="descr"> |
| Check for uninitialized arguments in function calls and Objective-C |
| message expressions.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test(void) { |
| int t; |
| int &p = t; |
| int &s = p; |
| int &q = s; |
| foo(q); // warn |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| void test(void) { |
| int x; |
| foo(&x); // warn |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.core.CastSize"><div class="namedescr expandable"><span class="name"> |
| alpha.core.CastSize</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check when casting a malloc'ed type T, whether the size is a multiple of the |
| size of T (Works only with <span class="name">unix.Malloc</span> |
| or <span class="name">alpha.unix.MallocWithAnnotations</span> |
| checks enabled).</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test() { |
| int *x = (int *)malloc(11); // warn |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.core.CastToStruct"><div class="namedescr expandable"><span class="name"> |
| alpha.core.CastToStruct</span><span class="lang"> |
| (C, C++)</span><div class="descr"> |
| Check for cast from non-struct pointer to struct pointer.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| // C |
| struct s {}; |
| |
| void test(int *p) { |
| struct s *ps = (struct s *) p; // warn |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| // C++ |
| class c {}; |
| |
| void test(int *p) { |
| c *pc = (c *) p; // warn |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.core.Conversion"><div class="namedescr expandable"><span class="name"> |
| alpha.core.Conversion</span><span class="lang"> |
| (C, C++, ObjC)</span><div class="descr"> |
| Loss of sign or precision in implicit conversions</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test(unsigned U, signed S) { |
| if (S > 10) { |
| if (U < S) { |
| } |
| } |
| if (S < -10) { |
| if (U < S) { // warn (loss of sign) |
| } |
| } |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| void test() { |
| long long A = 1LL << 60; |
| short X = A; // warn (loss of precision) |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.core.DynamicTypeChecker"><div class="namedescr expandable"><span class="name"> |
| alpha.core.DynamicTypeChecker</span><span class="lang"> |
| (ObjC)</span><div class="descr"> |
| Check for cases where the dynamic and the static type of an |
| object are unrelated.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| id date = [NSDate date]; |
| |
| // Warning: Object has a dynamic type 'NSDate *' which is |
| // incompatible with static type 'NSNumber *'" |
| NSNumber *number = date; |
| [number doubleValue]; |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.core.FixedAddr"><div class="namedescr expandable"><span class="name"> |
| alpha.core.FixedAddr</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check for assignment of a fixed address to a pointer.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test() { |
| int *p; |
| p = (int *) 0x10000; // warn |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.core.IdenticalExpr"><div class="namedescr expandable"><span class="name"> |
| alpha.core.IdenticalExpr</span><span class="lang"> |
| (C, C++)</span><div class="descr"> |
| Warn about suspicious uses of identical expressions.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| // C |
| void test() { |
| int a = 5; |
| int b = a | 4 | a; // warn: identical expr on both sides |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| // 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()); |
| } |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.core.PointerArithm"><div class="namedescr expandable"><span class="name"> |
| alpha.core.PointerArithm</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check for pointer arithmetic on locations other than array |
| elements.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test() { |
| int x; |
| int *p; |
| p = &x + 1; // warn |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.core.PointerSub"><div class="namedescr expandable"><span class="name"> |
| alpha.core.PointerSub</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check for pointer subtractions on two pointers pointing to different memory |
| chunks.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test() { |
| int x, y; |
| int d = &y - &x; // warn |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.core.SizeofPtr"><div class="namedescr expandable"><span class="name"> |
| alpha.core.SizeofPtr</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Warn about unintended use of <code>sizeof()</code> on pointer |
| expressions.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| struct s {}; |
| |
| int test(struct s *p) { |
| return sizeof(p); |
| // warn: sizeof(ptr) can produce an unexpected result |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.core.StackAddressAsyncEscape"><div class="namedescr expandable"><span class="name"> |
| alpha.core.StackAddressAsyncEscape</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check that addresses to stack memory do not escape the function that involves |
| <code>dispatch_after</code> or <code>dispatch_async</code>. This checker is |
| a part of core.StackAddressEscape, but is |
| <a href=https://reviews.llvm.org/D41042>temporarily disabled</a> until some |
| false positives are fixed.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| dispatch_block_t test_block_inside_block_async_leak() { |
| int x = 123; |
| void (^inner)(void) = ^void(void) { |
| int y = x; |
| ++y; |
| }; |
| void (^outer)(void) = ^void(void) { |
| int z = x; |
| ++z; |
| inner(); |
| }; |
| return outer; // warn: address of stack-allocated block is captured by a |
| // returned block |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.core.TestAfterDivZero"><div class="namedescr expandable"><span class="name"> |
| alpha.core.TestAfterDivZero</span><span class="lang"> |
| (C, C++, ObjC)</span><div class="descr"> |
| Check for division by variable that is later compared against 0. |
| Either the comparison is useless or there is division by zero. |
| </div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test(int x) { |
| var = 77 / x; |
| if (x == 0) { } // warn |
| } |
| </pre></div></div></td></tr> |
| |
| |
| </tbody></table> |
| |
| <!-- =========================== cplusplus alpha =========================== --> |
| <h3 id="cplusplus_alpha_checkers">C++ Alpha Checkers</h3> |
| <table class="checkers"> |
| <colgroup><col class="namedescr"><col class="example"></colgroup> |
| <thead><tr><td>Name, Description</td><td>Example</td></tr></thead> |
| <tbody> |
| |
| |
| <tr><td><a id="alpha.cplusplus.DeleteWithNonVirtualDtor"><div class="namedescr expandable"><span class="name"> |
| alpha.cplusplus.DeleteWithNonVirtualDtor</span><span class="lang"> |
| (C++)</span><div class="descr"> |
| Reports destructions of polymorphic objects with a non-virtual destructor in |
| their base class |
| </div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| NonVirtual *create() { |
| NonVirtual *x = new NVDerived(); // note: conversion from derived to base |
| // happened here |
| return x; |
| } |
| |
| void sink(NonVirtual *x) { |
| delete x; // warn: destruction of a polymorphic object with no virtual |
| // destructor |
| } |
| </pre></div></div></td></tr> |
| |
| <tr><td><a id="alpha.cplusplus.EnumCastOutOfRange"><div class="namedescr expandable"><span class="name"> |
| alpha.cplusplus.EnumCastOutOfRange</span><span class="lang"> |
| (C++)</span><div class="descr"> |
| Check for integer to enumeration casts that could result in undefined values. |
| </div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| enum TestEnum { |
| A = 0 |
| }; |
| |
| void foo() { |
| TestEnum t = static_cast<TestEnum>(-1); |
| // warn: the value provided to the cast expression is not in |
| the valid range of values for the enum |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.cplusplus.InvalidatedIterator"><div class="namedescr expandable"><span class="name"> |
| alpha.cplusplus.InvalidatedIterator</span><span class="lang"> |
| (C++)</span><div class="descr"> |
| Check for use of invalidated iterators. |
| </div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void bad_copy_assign_operator_list1(std::list<int> &L1, |
| const std::list<int> &L2) { |
| auto i0 = L1.cbegin(); |
| L1 = L2; |
| *i0; // warn: invalidated iterator accessed |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.cplusplus.IteratorRange"><div class="namedescr expandable"><span class="name"> |
| alpha.cplusplus.IteratorRange</span><span class="lang"> |
| (C++)</span><div class="descr"> |
| Check for iterators used outside their valid ranges. |
| </div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void simple_bad_end(const std::vector<int> &v) { |
| auto i = v.end(); |
| *i; // warn: iterator accessed outside of its range |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.cplusplus.MismatchedIterator"><div class="namedescr expandable"><span class="name"> |
| alpha.cplusplus.MismatchedIterator</span><span class="lang"> |
| (C++)</span><div class="descr"> |
| Check for use of iterators of different containers where iterators of the same |
| container are expected. |
| </div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void bad_insert3(std::vector<int> &v1, std::vector<int> &v2) { |
| v2.insert(v1.cbegin(), v2.cbegin(), v2.cend()); // warn: container accessed |
| // using foreign |
| // iterator argument |
| v1.insert(v1.cbegin(), v1.cbegin(), v2.cend()); // warn: iterators of |
| // different containers |
| // used where the same |
| // container is |
| // expected |
| v1.insert(v1.cbegin(), v2.cbegin(), v1.cend()); // warn: iterators of |
| // different containers |
| // used where the same |
| // container is |
| // expected |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.cplusplus.Move"><div class="namedescr expandable"><span class="name"> |
| alpha.cplusplus.Move</span><span class="lang"> |
| (C++)</span><div class="descr"> |
| Method calls on a moved-from object and copying a moved-from object will be |
| reported. |
| </div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| struct A { |
| void foo() {} |
| }; |
| |
| void f() { |
| A a; |
| A b = std::move(a); // note: 'a' became 'moved-from' here |
| a.foo(); // warn: method call on a 'moved-from' object 'a' |
| } |
| </pre></div></div></td></tr> |
| |
| |
| </tbody></table> |
| |
| |
| <!-- =========================== dead code alpha =========================== --> |
| <h3 id="deadcode_alpha_checkers">Dead Code Alpha Checkers</h3> |
| <table class="checkers"> |
| <colgroup><col class="namedescr"><col class="example"></colgroup> |
| <thead><tr><td>Name, Description</td><td>Example</td></tr></thead> |
| |
| <tbody> |
| <tr><td><a id="alpha.deadcode.UnreachableCode"><div class="namedescr expandable"><span class="name"> |
| alpha.deadcode.UnreachableCode</span><span class="lang"> |
| (C, C++, ObjC)</span><div class="descr"> |
| Check unreachable code.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| // C |
| int test() { |
| int x = 1; |
| while(x); |
| return x; // warn |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| // C++ |
| void test() { |
| int a = 2; |
| |
| while (a > 1) |
| a--; |
| |
| if (a > 1) |
| a++; // warn |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| // Objective-C |
| void test(id x) { |
| return; |
| [x retain]; // warn |
| } |
| </pre></div></div></td></tr> |
| </tbody></table> |
| |
| <!-- =========================== llvm alpha =========================== --> |
| <h3 id="llvm_alpha_checkers">LLVM Checkers</h3> |
| <table class="checkers"> |
| <colgroup><col class="namedescr"><col class="example"></colgroup> |
| <thead><tr><td>Name, Description</td><td>Example</td></tr></thead> |
| |
| <tbody> |
| <tr><td><a id="alpha.llvm.Conventions"><div class="namedescr expandable"><span class="name"> |
| alpha.llvm.Conventions</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check code for LLVM codebase conventions: |
| <ul> |
| <li>A <code>StringRef</code> should not be bound to a temporary std::string |
| whose lifetime is shorter than the <code>StringRef</code>'s.</li> |
| <li>Clang AST nodes should not have fields that can allocate memory.</li> |
| </ul> |
| </div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| <!-- TODO: Add examples, as currently it's hard to get this checker working. --> |
| </pre></div></div></td></tr> |
| |
| </tbody></table> |
| |
| |
| <!-- ============================== OS X alpha ============================== --> |
| <h3 id="osx_alpha_checkers">OS X Alpha Checkers</h3> |
| <table class="checkers"> |
| <colgroup><col class="namedescr"><col class="example"></colgroup> |
| <thead><tr><td>Name, Description</td><td>Example</td></tr></thead> |
| |
| <tbody> |
| <tr><td><a id="alpha.osx.cocoa.DirectIvarAssignment"><div class="namedescr expandable"><span class="name"> |
| alpha.osx.cocoa.DirectIvarAssignment</span><span class="lang"> |
| (ObjC)</span><div class="descr"> |
| Check that Objective C properties follow the following rule: the property |
| should be set with the setter, not though a direct assignment.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| @interface MyClass : NSObject {} |
| @property (readonly) id A; |
| - (void) foo; |
| @end |
| |
| @implementation MyClass |
| - (void) foo { |
| _A = 0; // warn |
| } |
| @end |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions"><div class="namedescr expandable"><span class="name"> |
| alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions</span><span class="lang"> |
| (ObjC)</span><div class="descr"> |
| Check for direct assignments to instance variables in the methods annotated |
| with <code>objc_no_direct_instance_variable_assignment</code>.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| @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 |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.osx.cocoa.InstanceVariableInvalidation"><div class="namedescr expandable"><span class="name"> |
| alpha.osx.cocoa.InstanceVariableInvalidation</span><span class="lang"> |
| (ObjC)</span><div class="descr"> |
| Check that the invalidatable instance variables are invalidated in the methods |
| annotated with <code>objc_instance_variable_invalidator</code>.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| @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 |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.osx.cocoa.MissingInvalidationMethod"><div class="namedescr expandable"><span class="name"> |
| alpha.osx.cocoa.MissingInvalidationMethod</span><span class="lang"> |
| (ObjC)</span><div class="descr"> |
| Check that the invalidation methods are present in classes that contain |
| invalidatable instance variables.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| @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 |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.osx.cocoa.localizability.PluralMisuseChecker"><div class="namedescr expandable"><span class="name"> |
| alpha.osx.cocoa.localizability.PluralMisuseChecker</span><span class="lang"> |
| (ObjC)</span><div class="descr"> |
| Warns against using one vs. many plural pattern in code |
| when generating localized strings. |
| </div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| NSString *reminderText = |
| NSLocalizedString(@"None", @"Indicates no reminders"); |
| if (reminderCount == 1) { |
| // Warning: Plural cases are not supported across all languages. |
| // Use a .stringsdict file instead |
| reminderText = |
| NSLocalizedString(@"1 Reminder", @"Indicates single reminder"); |
| } else if (reminderCount >= 2) { |
| // Warning: Plural cases are not supported across all languages. |
| // Use a .stringsdict file instead |
| reminderText = |
| [NSString stringWithFormat: |
| NSLocalizedString(@"%@ Reminders", @"Indicates multiple reminders"), |
| reminderCount]; |
| } |
| </pre></div></div></td></tr> |
| |
| </tbody></table> |
| |
| <!-- =========================== security alpha =========================== --> |
| <h3 id="security_alpha_checkers">Security Alpha Checkers</h3> |
| <table class="checkers"> |
| <colgroup><col class="namedescr"><col class="example"></colgroup> |
| <thead><tr><td>Name, Description</td><td>Example</td></tr></thead> |
| |
| <tbody> |
| <tr><td><a id="alpha.security.ArrayBound"><div class="namedescr expandable"><span class="name"> |
| alpha.security.ArrayBound</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Warn about buffer overflows (older checker).</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test() { |
| char *s = ""; |
| char c = s[1]; // warn |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| 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 |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| // note: requires unix.Malloc or |
| // alpha.unix.MallocWithAnnotations checks enabled. |
| void test() { |
| int *p = malloc(12); |
| p[3] = 4; // warn |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| void test() { |
| char a[2]; |
| int *b = (int*)a; |
| b[1] = 3; // warn |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.security.ArrayBoundV2"><div class="namedescr expandable"><span class="name"> |
| alpha.security.ArrayBoundV2</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Warn about buffer overflows (newer checker).</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test() { |
| char *s = ""; |
| char c = s[1]; // warn |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| void test() { |
| int buf[100]; |
| int *p = buf; |
| p = p + 99; |
| p[1] = 1; // warn |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| // 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 |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| // note: requires alpha.security.taint check turned on. |
| void test() { |
| char s[] = "abc"; |
| int x = getchar(); |
| char c = s[x]; // warn: index is tainted |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.security.MallocOverflow"><div class="namedescr expandable"><span class="name"> |
| alpha.security.MallocOverflow</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check for overflows in the arguments to <code>malloc()</code>.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test(int n) { |
| void *p = malloc(n * sizeof(int)); // warn |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.security.MmapWriteExec"><div class="namedescr expandable"><span class="name"> |
| alpha.security.MmapWriteExec</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Warn on <code>mmap()<code> calls that are both writable and executable. |
| </div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test(int n) { |
| void *c = mmap(NULL, 32, PROT_READ | PROT_WRITE | PROT_EXEC, |
| MAP_PRIVATE | MAP_ANON, -1, 0); |
| // warn: Both PROT_WRITE and PROT_EXEC flags are set. This can lead to |
| // exploitable memory regions, which could be overwritten with malicious |
| // code |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.security.ReturnPtrRange"><div class="namedescr expandable"><span class="name"> |
| alpha.security.ReturnPtrRange</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check for an out-of-bound pointer being returned to callers.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| static int A[10]; |
| |
| int *test() { |
| int *p = A + 10; |
| return p; // warn |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| int test(void) { |
| int x; |
| return x; // warn: undefined or garbage returned |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.security.taint.TaintPropagation"><div class="namedescr expandable"><span class="name"> |
| alpha.security.taint.TaintPropagation</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Generate taint information used by other checkers.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test() { |
| char x = getchar(); // 'x' marked as tainted |
| system(&x); // warn: untrusted data is passed to a system call |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| // 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 |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| void test() { |
| size_t ts; |
| scanf("%zd", &ts); // 'ts' marked as tainted |
| int *p = (int *)malloc(ts * sizeof(int)); |
| // warn: untrusted data as buffer size |
| } |
| </pre></div></div></td></tr> |
| |
| </tbody></table> |
| |
| <!-- ============================= unix alpha ============================= --> |
| <h3 id="unix_alpha_checkers">Unix Alpha Checkers</h3> |
| <table class="checkers"> |
| <colgroup><col class="namedescr"><col class="example"></colgroup> |
| <thead><tr><td>Name, Description</td><td>Example</td></tr></thead> |
| <tbody> |
| |
| |
| <tr><td><a id="alpha.unix.BlockInCriticalSection"><div class="namedescr expandable"><span class="name"> |
| alpha.unix.BlockInCriticalSection</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check for calls to blocking functions inside a critical section. Applies to: |
| <div class=functions> |
| lock<br> |
| unlock<br> |
| sleep<br> |
| getc<br> |
| fgets<br> |
| read<br> |
| revc<br> |
| pthread_mutex_lock<br> |
| pthread_mutex_unlock<br> |
| mtx_lock<br> |
| mtx_timedlock<br> |
| mtx_trylock<br> |
| mtx_unlock<br> |
| lock_guard<br> |
| unique_lock</div> |
| </div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test() { |
| std::mutex m; |
| m.lock(); |
| sleep(3); // warn: a blocking function sleep is called inside a critical |
| // section |
| m.unlock(); |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.unix.Chroot"><div class="namedescr expandable"><span class="name"> |
| alpha.unix.Chroot</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check improper use of <code>chroot</code>.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void f(); |
| |
| void test() { |
| chroot("/usr/local"); |
| f(); // warn: no call of chdir("/") immediately after chroot |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.unix.PthreadLock"><div class="namedescr expandable"><span class="name"> |
| alpha.unix.PthreadLock</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Simple lock -> unlock checker; applies to:<div class=functions> |
| pthread_mutex_lock<br> |
| pthread_rwlock_rdlock<br> |
| pthread_rwlock_wrlock<br> |
| lck_mtx_lock<br> |
| lck_rw_lock_exclusive<br> |
| lck_rw_lock_shared<br> |
| pthread_mutex_trylock<br> |
| pthread_rwlock_tryrdlock<br> |
| pthread_rwlock_tryrwlock<br> |
| lck_mtx_try_lock<br> |
| lck_rw_try_lock_exclusive<br> |
| lck_rw_try_lock_shared<br> |
| pthread_mutex_unlock<br> |
| pthread_rwlock_unlock<br> |
| lck_mtx_unlock<br> |
| lck_rw_done</div></div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| pthread_mutex_t mtx; |
| |
| void test() { |
| pthread_mutex_lock(&mtx); |
| pthread_mutex_lock(&mtx); |
| // warn: this lock has already been acquired |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| 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 |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| 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 |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.unix.SimpleStream"><div class="namedescr expandable"><span class="name"> |
| alpha.unix.SimpleStream</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check for misuses of stream APIs:<div class=functions> |
| fopen<br> |
| fclose</div>(demo checker, the subject of the demo |
| (<a href="http://llvm.org/devmtg/2012-11/Zaks-Rose-Checker24Hours.pdf">Slides</a> |
| ,<a href="https://youtu.be/kdxlsP5QVPw">Video</a>) |
| by Anna Zaks and Jordan Rose presented at the <a href="http://llvm.org/devmtg/2012-11/"> |
| 2012 LLVM Developers' Meeting).</a></div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test() { |
| FILE *F = fopen("myfile.txt", "w"); |
| } // warn: opened file is never closed |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| void test() { |
| FILE *F = fopen("myfile.txt", "w"); |
| |
| if (F) |
| fclose(F); |
| |
| fclose(F); // warn: closing a previously closed file stream |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.unix.Stream"><div class="namedescr expandable"><span class="name"> |
| alpha.unix.Stream</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check stream handling functions:<div class=functions>fopen<br> |
| tmpfile<br> |
| fclose<br> |
| fread<br> |
| fwrite<br> |
| fseek<br> |
| ftell<br> |
| rewind<br> |
| fgetpos<br> |
| fsetpos<br> |
| clearerr<br> |
| feof<br> |
| ferror<br> |
| fileno</div></div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test() { |
| FILE *p = fopen("foo", "r"); |
| } // warn: opened file is never closed |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| void test() { |
| FILE *p = fopen("foo", "r"); |
| fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL |
| fclose(p); |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| 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); |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| void test() { |
| FILE *p = fopen("foo", "r"); |
| fclose(p); |
| fclose(p); // warn: already closed |
| } |
| </pre></div><div class="separator"></div> |
| <div class="example"><pre> |
| void test() { |
| FILE *p = tmpfile(); |
| ftell(p); // warn: stream pointer might be NULL |
| fclose(p); |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.unix.cstring.BufferOverlap"><div class="namedescr expandable"><span class="name"> |
| alpha.unix.cstring.BufferOverlap</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Checks for overlap in two buffer arguments; applies to:<div class=functions> |
| memcpy<br> |
| mempcpy</div></div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test() { |
| int a[4] = {0}; |
| memcpy(a + 2, a + 1, 8); // warn |
| } |
| </pre></div></div></td></tr> |
| |
| |
| <tr><td><a id="alpha.unix.cstring.NotNullTerminated"><div class="namedescr expandable"><span class="name"> |
| alpha.unix.cstring.NotNullTerminated</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check for arguments which are not null-terminated strings; applies |
| to:<div class=functions> |
| strlen<br> |
| strnlen<br> |
| strcpy<br> |
| strncpy<br> |
| strcat<br> |
| strncat</div></div></div></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test() { |
| int y = strlen((char *)&test); // warn |
| } |
| </pre></div></div></a></td></tr> |
| |
| |
| <tr><td><a id="alpha.unix.cstring.OutOfBounds"><div class="namedescr expandable"><span class="name"> |
| alpha.unix.cstring.OutOfBounds</span><span class="lang"> |
| (C)</span><div class="descr"> |
| Check for out-of-bounds access in string functions; applies |
| to:<div class=functions> |
| strncopy<br> |
| strncat</div></div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| void test(char *y) { |
| char x[4]; |
| if (strlen(y) == 4) |
| strncpy(x, y, 5); // warn |
| } |
| </pre></div></div></td></tr> |
| |
| </tbody></table> |
| |
| <!-- =========================== nondeterminism alpha =========================== --> |
| <h3 id="nondeterminism_alpha_checkers">Non-determinism Alpha Checkers</h3> |
| <table class="checkers"> |
| <colgroup><col class="namedescr"><col class="example"></colgroup> |
| <thead><tr><td>Name, Description</td><td>Example</td></tr></thead> |
| |
| <tbody> |
| <tr><td><a id="alpha.nondeterminism.PointerIteration"><div class="namedescr expandable"><span class="name"> |
| alpha.nondeterminism.PointerIteration</span><span class="lang"> |
| (C++)</span><div class="descr"> |
| Check for non-determinism caused by iterating unordered containers of pointers.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| // C++ |
| void test() { |
| int a = 1, b = 2; |
| std::unordered_set<int *> UnorderedPtrSet = {&a, &b}; |
| |
| for (auto i : UnorderedPtrSet) // warn |
| f(i); |
| } |
| </pre></div></div></td></tr> |
| </tbody></table> |
| |
| <tbody> |
| <tr><td><a id="alpha.nondeterminism.PointerSorting"><div class="namedescr expandable"><span class="name"> |
| alpha.nondeterminism.PointerSorting</span><span class="lang"> |
| (C++)</span><div class="descr"> |
| Check for non-determinism caused by sorting of pointers.</div></div></a></td> |
| <td><div class="exampleContainer expandable"> |
| <div class="example"><pre> |
| // C++ |
| void test() { |
| int a = 1, b = 2; |
| std::vector<int *> V = {&a, &b}; |
| std::sort(V.begin(), V.end()); // warn |
| } |
| </pre></div></div></td></tr> |
| </tbody></table> |
| |
| </div> <!-- page --> |
| </div> <!-- content --> |
| </body> |
| </html> |