Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f210586

Browse files
committed
[zlaski/pointer-overflow-check] Enhance qhelp and test case.
1 parent 1f82ea7 commit f210586

6 files changed

Lines changed: 39 additions & 25 deletions

File tree

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
bool check_pointer_overflow(P *ptr) {
2-
return ptr + 0x12345678 < ptr; // BAD
1+
bool not_in_range(T *ptr, size_t a) {
2+
return ptr + a < ptr; // BAD
33
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
bool check_pointer_overflow(P *ptr, P *ptr_end) {
2-
return ptr_end - ptr >= 4; // GOOD
3-
}
1+
bool in_range(T *ptr, T *ptr_end, size_t a) {
2+
return a < ptr_end - ptr; // GOOD
3+
}

cpp/ql/src/Likely Bugs/Memory Management/PointerOverflowCheck.qhelp

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,36 +12,39 @@ which has undefined behavior. In fact, many optimizing compilers will remove
1212
(<code>false</code>). Conversely, should <code>p + a</code> <i>not</i> overflow,
1313
the programmer may erroneously assume that the memory location <code>p + a</code>
1414
is accessible to the program, even though it may be inaccessible (protected by
15-
the operating system) or nonexistent.
15+
the operating system) or nonexistent; writing to such memory, if allowed, can
16+
lead to memory corruption.
1617
</p>
1718
</overview>
1819
<recommendation>
1920
<p>
20-
When checking for an out-of-range pointer, compare the pointer
21-
value <code>p</code> against a known pointer value <code>p_max</code> representing
22-
the highest allowable memory address. The <code>p_max</code> pointer should
23-
point inside or just past the end of a defined memory region, such that
24-
<code>p + a &lt;= p_max</code>. Since we do not wish to evaluate <code>p + a</code>
25-
(which may result in undefined behavior), we rewrite the inequality as
26-
<code>p_max - p &gt; a</code>.
27-
</p>
21+
To check whether an index <code>a</code> is less than the length of an array,
22+
simply compare these two numbers as unsigned integers: <code>a &lt; ARRAY_LENGTH</code>.
23+
If the length of the array is defined as the difference between two pointers
24+
<code>p</code> and <code>p_end</code>, write <code>a &lt; p_end - p</code>.
25+
If a is <code>signed</code>, cast it to <code>unsigned</code>
26+
in order to guard against negative <code>a</code>. For example, write
27+
<code>(size_t)a &lt; p_end - p</code>.</p>
2828
</recommendation>
2929
<example>
3030
<p>
31-
In the first example, a constant value is being added to a pointer and
32-
then tested for "wrap around". Should the test fail, the developer
33-
might assume that memory location <code>ptr + 0x12345678</code> is a
34-
valid one for the program to use, even though it may be either
35-
inaccessible (protected from the current process by the operating
36-
system) or nonexistent. Furthermore, it may be impossible to tell when
37-
the test succeeds, since pointer overflow has undefined behavior.
31+
In the first example, an index <code>a</code>is being added to a pointer <code>p</code>
32+
to an array with elements of type <code>T</code>. Since we are not provided a
33+
separate pointer pointing to the end of the array, we fall back
34+
on a check for address "wrap-around" to see if <code>p + a</code> points at
35+
valid memory. This scheme does not work, unfortunately, since the
36+
value of <code>p + a</code> is undefined if it points at invalid memory (for
37+
example, outside our array). Even if <code>p + a</code> were to point to
38+
some accessible memory location, it would almost certainly lie
39+
<i>outside</i> the bounds of the array.
3840
</p>
3941
<sample src="PointerOverflowCheck-bad.cpp" />
4042
<p>
4143
The next example shows how to properly check for an out-of-range pointer.
4244
In order to do so, we need to obtain the value <code>ptr_end</code>
43-
representing the highest allowable memory address. In this case,
44-
the address lies just beyond the end of an array.
45+
representing the end of the array (or the address immediately past
46+
the end). We can then express the condition <code>p + a &lt; p_end</code> as a
47+
difference of two pointers, even if <code>p + a</code> happens to be undefined.
4548
</p>
4649
<sample src="PointerOverflowCheck-good.cpp" />
4750
</example>

cpp/ql/src/Likely Bugs/Memory Management/PointerOverflowCheck.ql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/**
2-
* @name Dangerous pointer out-of-range check
2+
* @name Reliance on pointer wrap-around
33
* @description Testing for out-of-range pointers by adding a value to a pointer
44
* to see if it "wraps around" is dangerous because it relies
55
* on undefined behavior and may lead to attempted use of
66
* nonexistent or inaccessible memory locations.
77
* @kind problem
8-
* @problem.severity warning
8+
* @problem.severity error
99
* @precision high
1010
* @id cpp/pointer-overflow-check
1111
* @tags reliability
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
| test.cpp:6:12:6:33 | ... < ... | Pointer out-of-range check relying on pointer overflow is undefined. |
2+
| test.cpp:32:12:32:24 | ... < ... | Pointer out-of-range check relying on pointer overflow is undefined. |

cpp/ql/test/query-tests/Likely Bugs/Memory Management/PointerOverflowCheck/test.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,13 @@ void foo(int untrusted_int) {
2525
q.begin() + untrusted_int < q.begin()) // BAD [NOT DETECTED]
2626
throw q;
2727
}
28+
29+
typedef unsigned long long size_t;
30+
31+
bool not_in_range(Q *ptr, size_t a) {
32+
return ptr + a < ptr; // BAD
33+
}
34+
35+
bool in_range(Q *ptr, Q *ptr_end, size_t a) {
36+
return a < ptr_end - ptr; // GOOD
37+
}

0 commit comments

Comments
 (0)