aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer/bounds-checking.cc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2022-11-30 21:26:42 -0500
committerDavid Malcolm <dmalcolm@redhat.com>2022-11-30 21:26:42 -0500
commit7c655699ed51b0c987e5472767db48b19044ae05 (patch)
tree1576cbce7ffb4aefba1d1b637d885b826ccbe204 /gcc/analyzer/bounds-checking.cc
parentd69a95c12cc91ec10d6a8c78f401bf6720b08fce (diff)
downloadgcc-7c655699ed51b0c987e5472767db48b19044ae05.zip
gcc-7c655699ed51b0c987e5472767db48b19044ae05.tar.gz
gcc-7c655699ed51b0c987e5472767db48b19044ae05.tar.bz2
analyzer: add note about valid subscripts [PR106626]
Consider -fanalyzer on: #include <stdint.h> int32_t arr[10]; void int_arr_write_element_after_end_off_by_one(int32_t x) { arr[10] = x; } Trunk x86_64: https://godbolt.org/z/17zn3qYY4 Currently we emit: <source>: In function 'int_arr_write_element_after_end_off_by_one': <source>:7:11: warning: buffer overflow [CWE-787] [-Wanalyzer-out-of-bounds] 7 | arr[10] = x; | ~~~~~~~~^~~ event 1 | | 3 | int32_t arr[10]; | | ^~~ | | | | | (1) capacity is 40 bytes | +--> 'int_arr_write_element_after_end_off_by_one': events 2-3 | | 5 | void int_arr_write_element_after_end_off_by_one(int32_t x) | | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | | | (2) entry to 'int_arr_write_element_after_end_off_by_one' | 6 | { | 7 | arr[10] = x; | | ~~~~~~~~~~~ | | | | | (3) out-of-bounds write from byte 40 till byte 43 but 'arr' ends at byte 40 | <source>:7:11: note: write of 4 bytes to beyond the end of 'arr' 7 | arr[10] = x; | ~~~~~~~~^~~ This is worded in terms of bytes, due to the way -Wanalyzer-out-of-bounds is implemented, but this isn't what the user wrote. This patch tries to get closer to the user's code by adding a note about array bounds when we're referring to an array. In the above example it adds this trailing note: note: valid subscripts for 'arr' are '[0]' to '[9]' gcc/analyzer/ChangeLog: PR analyzer/106626 * bounds-checking.cc (out_of_bounds::maybe_describe_array_bounds): New. (buffer_overflow::emit): Call maybe_describe_array_bounds. (buffer_overread::emit): Likewise. (buffer_underflow::emit): Likewise. (buffer_underread::emit): Likewise. gcc/testsuite/ChangeLog: PR analyzer/106626 * gcc.dg/analyzer/call-summaries-2.c: Add dg-message for expected note about valid indexes. * gcc.dg/analyzer/out-of-bounds-1.c: Likewise, fixing up existing dg-message directives. * gcc.dg/analyzer/out-of-bounds-write-char-arr.c: Likewise. * gcc.dg/analyzer/out-of-bounds-write-int-arr.c: Likewise. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc/analyzer/bounds-checking.cc')
-rw-r--r--gcc/analyzer/bounds-checking.cc46
1 files changed, 42 insertions, 4 deletions
diff --git a/gcc/analyzer/bounds-checking.cc b/gcc/analyzer/bounds-checking.cc
index ad7f431..b02bc79 100644
--- a/gcc/analyzer/bounds-checking.cc
+++ b/gcc/analyzer/bounds-checking.cc
@@ -71,6 +71,34 @@ public:
}
protected:
+ /* Potentially add a note about valid ways to index this array, such
+ as (given "int arr[10];"):
+ note: valid subscripts for 'arr' are '[0]' to '[9]'
+ We print the '[' and ']' characters so as to express the valid
+ subscripts using C syntax, rather than just as byte ranges,
+ which hopefully is more clear to the user. */
+ void
+ maybe_describe_array_bounds (location_t loc) const
+ {
+ if (!m_diag_arg)
+ return;
+ tree t = TREE_TYPE (m_diag_arg);
+ if (!t)
+ return;
+ if (TREE_CODE (t) != ARRAY_TYPE)
+ return;
+ tree domain = TYPE_DOMAIN (t);
+ if (!domain)
+ return;
+ tree max_idx = TYPE_MAX_VALUE (domain);
+ if (!max_idx)
+ return;
+ tree min_idx = TYPE_MIN_VALUE (domain);
+ inform (loc,
+ "valid subscripts for %qE are %<[%E]%> to %<[%E]%>",
+ m_diag_arg, min_idx, max_idx);
+ }
+
const region *m_reg;
tree m_diag_arg;
byte_range m_out_of_bounds_range;
@@ -165,6 +193,8 @@ public:
inform (rich_loc->get_loc (),
"write to beyond the end of %qE",
m_diag_arg);
+
+ maybe_describe_array_bounds (rich_loc->get_loc ());
}
return warned;
@@ -245,6 +275,8 @@ public:
inform (rich_loc->get_loc (),
"read from after the end of %qE",
m_diag_arg);
+
+ maybe_describe_array_bounds (rich_loc->get_loc ());
}
return warned;
@@ -297,8 +329,11 @@ public:
{
diagnostic_metadata m;
m.add_cwe (124);
- return warning_meta (rich_loc, m, get_controlling_option (),
- "buffer underflow");
+ bool warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "buffer underflow");
+ if (warned)
+ maybe_describe_array_bounds (rich_loc->get_loc ());
+ return warned;
}
label_text describe_final_event (const evdesc::final_event &ev)
@@ -346,8 +381,11 @@ public:
{
diagnostic_metadata m;
m.add_cwe (127);
- return warning_meta (rich_loc, m, get_controlling_option (),
- "buffer underread");
+ bool warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "buffer underread");
+ if (warned)
+ maybe_describe_array_bounds (rich_loc->get_loc ());
+ return warned;
}
label_text describe_final_event (const evdesc::final_event &ev)