1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
|
// RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-output=text \
// RUN: -analyzer-checker=core,alpha.security.ArrayBoundV2,unix.Malloc,alpha.security.taint -verify %s
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];
// FIXME: The following note does not appear:
// {{Assuming byte offset is non-negative and less than 40, the extent of 'TenElements'}}
// It seems that the analyzer "gives up" modeling this pointer arithmetics
// and says that `p[arg]` is just an UnknownVal (instead of calculating that
// it's equivalent to `TenElements[2+arg]`).
int b = TenElements[arg]; // This is normal access, and only the lower bound is new.
// expected-note@-1 {{Assuming index is non-negative}}
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 negative byte offset}}
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 negative byte offset}}
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 negative byte offset}}
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 negative byte offset}}
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}}
}
|