| // RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-output=text \ |
| // RUN: -analyzer-checker=core,security.ArrayBound,unix.Malloc,optin.taint -verify %s |
| |
| // When the checker security.ArrayBound encounters an array subscript operation |
| // that _may be_ in bounds, it assumes that indexing _is_ in bound. These |
| // assumptions will be reported to the user if the execution path leads to a |
| // bug report (made by any checker) and the symbol which was constrainted by |
| // the assumption is marked as interesting (with `markInteresting` or |
| // indirectly via `trackExpressionValue`) in that bug report. |
| // |
| // This test file validates the content of these note tags which describe the |
| // assumptions for the user. |
| |
| int TenElements[10]; |
| |
| int irrelevantAssumptions(int arg) { |
| int a = TenElements[arg]; |
| // Here the analyzer assumes that `arg` is in bounds, but doesn't report this |
| // because `arg` is not interesting for the bug. |
| int b = TenElements[13]; |
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} |
| // expected-note@-2 {{Access of 'TenElements' at index 13, while it holds only 10 'int' elements}} |
| return a + b; |
| } |
| |
| |
| int assumingBoth(int arg) { |
| int a = TenElements[arg]; |
| // expected-note@-1 {{Assuming index is non-negative and less than 10, the number of 'int' elements in 'TenElements'}} |
| int b = TenElements[arg]; // no additional note, we already assumed that 'arg' is in bounds |
| int c = TenElements[arg + 10]; |
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} |
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} |
| return a + b + c; |
| } |
| |
| int assumingBothPointerToMiddle(int arg) { |
| // If we're accessing an TenElements through a pointer pointing to its middle, the checker |
| // will speak about the "byte offset" measured from the beginning of the TenElements. |
| int *p = TenElements + 2; |
| int a = p[arg]; |
| // expected-note@-1 {{Assuming byte offset is non-negative and less than 40, the extent of 'TenElements'}} |
| |
| int b = TenElements[arg]; // This is normal access, and only the lower bound is new. |
| int c = TenElements[arg + 10]; |
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} |
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} |
| return a + b + c; |
| } |
| |
| int assumingLower(int arg) { |
| // expected-note@+2 {{Assuming 'arg' is < 10}} |
| // expected-note@+1 {{Taking false branch}} |
| if (arg >= 10) |
| return 0; |
| int a = TenElements[arg]; |
| // expected-note@-1 {{Assuming index is non-negative}} |
| int b = TenElements[arg + 10]; |
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} |
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} |
| return a + b; |
| } |
| |
| int assumingUpper(int arg) { |
| // expected-note@+2 {{Assuming 'arg' is >= 0}} |
| // expected-note@+1 {{Taking false branch}} |
| if (arg < 0) |
| return 0; |
| int a = TenElements[arg]; |
| // expected-note@-1 {{Assuming index is less than 10, the number of 'int' elements in 'TenElements'}} |
| int b = TenElements[arg - 10]; |
| // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}} |
| // expected-note@-2 {{Access of 'TenElements' at a negative index}} |
| return a + b; |
| } |
| |
| int assumingUpperIrrelevant(int arg) { |
| // FIXME: The assumption "assuming index is less than 10" is printed because |
| // it's assuming something about the interesting variable `arg`; however, |
| // it's irrelevant because in this testcase the out of bound access is |
| // deduced from the _lower_ bound on `arg`. Currently the analyzer cannot |
| // filter out assumptions that are logically irrelevant but "touch" |
| // interesting symbols; eventually it would be good to add support for this. |
| |
| // expected-note@+2 {{Assuming 'arg' is >= 0}} |
| // expected-note@+1 {{Taking false branch}} |
| if (arg < 0) |
| return 0; |
| int a = TenElements[arg]; |
| // expected-note@-1 {{Assuming index is less than 10, the number of 'int' elements in 'TenElements'}} |
| int b = TenElements[arg + 10]; |
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} |
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} |
| return a + b; |
| } |
| |
| int assumingUpperUnsigned(unsigned arg) { |
| int a = TenElements[arg]; |
| // expected-note@-1 {{Assuming index is less than 10, the number of 'int' elements in 'TenElements'}} |
| int b = TenElements[(int)arg - 10]; |
| // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}} |
| // expected-note@-2 {{Access of 'TenElements' at a negative index}} |
| return a + b; |
| } |
| |
| int assumingNothing(unsigned arg) { |
| // expected-note@+2 {{Assuming 'arg' is < 10}} |
| // expected-note@+1 {{Taking false branch}} |
| if (arg >= 10) |
| return 0; |
| int a = TenElements[arg]; // no note here, we already know that 'arg' is in bounds |
| int b = TenElements[(int)arg - 10]; |
| // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}} |
| // expected-note@-2 {{Access of 'TenElements' at a negative index}} |
| return a + b; |
| } |
| |
| short assumingConvertedToCharP(int arg) { |
| // When indices are reported, the note will use the element type that's the |
| // result type of the subscript operator. |
| char *cp = (char*)TenElements; |
| char a = cp[arg]; |
| // expected-note@-1 {{Assuming index is non-negative and less than 40, the number of 'char' elements in 'TenElements'}} |
| char b = cp[arg]; // no additional note, we already assumed that 'arg' is in bounds |
| char c = cp[arg + 40]; |
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} |
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 40 'char' elements}} |
| return a + b + c; |
| } |
| |
| struct foo { |
| int num; |
| char a[8]; |
| char b[5]; |
| }; |
| |
| int assumingConvertedToIntP(struct foo f, int arg) { |
| // When indices are reported, the note will use the element type that's the |
| // result type of the subscript operator. |
| int a = ((int*)(f.a))[arg]; |
| // expected-note@-1 {{Assuming index is non-negative and less than 2, the number of 'int' elements in 'f.a'}} |
| // However, if the extent of the memory region is not divisible by the |
| // element size, the checker measures the offset and extent in bytes. |
| int b = ((int*)(f.b))[arg]; |
| // expected-note@-1 {{Assuming byte offset is less than 5, the extent of 'f.b'}} |
| int c = TenElements[arg-2]; |
| // expected-warning@-1 {{Out of bound access to memory preceding 'TenElements'}} |
| // expected-note@-2 {{Access of 'TenElements' at a negative index}} |
| return a + b + c; |
| } |
| |
| int assumingPlainOffset(struct foo f, int arg) { |
| // This TC is intended to check the corner case that the checker prints the |
| // shorter "offset" instead of "byte offset" when it's irrelevant that the |
| // offset is measured in bytes. |
| |
| // expected-note@+2 {{Assuming 'arg' is < 2}} |
| // expected-note@+1 {{Taking false branch}} |
| if (arg >= 2) |
| return 0; |
| |
| int b = ((int*)(f.b))[arg]; |
| // expected-note@-1 {{Assuming byte offset is non-negative and less than 5, the extent of 'f.b'}} |
| // FIXME: this should be {{Assuming offset is non-negative}} |
| // but the current simplification algorithm doesn't realize that arg <= 1 |
| // implies that the byte offset arg*4 will be less than 5. |
| |
| int c = TenElements[arg+10]; |
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} |
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} |
| return b + c; |
| } |
| |
| typedef __typeof(sizeof(int)) size_t; |
| void *malloc(size_t size); |
| void free(void *ptr); |
| |
| int assumingExtent(int arg) { |
| // Verify that the assumption note is printed when the extent is interesting |
| // (even if the index isn't interesting). |
| int *mem = (int*)malloc(arg); |
| |
| mem[12] = 123; |
| // expected-note@-1 {{Assuming index '12' is less than the number of 'int' elements in the heap area}} |
| |
| free(mem); |
| |
| return TenElements[arg]; |
| // expected-warning@-1 {{Out of bound access to memory after the end of 'TenElements'}} |
| // expected-note@-2 {{Access of 'TenElements' at an overflowing index, while it holds only 10 'int' elements}} |
| } |
| |
| int *extentInterestingness(int arg) { |
| // Verify that in an out-of-bounds access issue the extent is marked as |
| // interesting (so assumptions about its value are printed). |
| int *mem = (int*)malloc(arg); |
| |
| TenElements[arg] = 123; |
| // expected-note@-1 {{Assuming index is non-negative and less than 10, the number of 'int' elements in 'TenElements'}} |
| |
| return &mem[12]; |
| // expected-warning@-1 {{Out of bound access to memory after the end of the heap area}} |
| // expected-note@-2 {{Access of 'int' element in the heap area at index 12}} |
| } |
| |
| int triggeredByAnyReport(int arg) { |
| // Verify that note tags explaining the assumptions made by ArrayBound are |
| // not limited to ArrayBound reports but will appear on any bug report (that |
| // marks the relevant symbol as interesting). |
| TenElements[arg + 10] = 8; |
| // expected-note@-1 {{Assuming index is non-negative and less than 10, the number of 'int' elements in 'TenElements'}} |
| return 1024 >> arg; |
| // expected-warning@-1 {{Right operand is negative in right shift}} |
| // expected-note@-2 {{The result of right shift is undefined because the right operand is negative}} |
| } |