aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/analyzer/region-model-manager.cc53
-rw-r--r--gcc/analyzer/region-model-manager.h4
-rw-r--r--gcc/analyzer/region-model.cc1
-rw-r--r--gcc/analyzer/store.cc35
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/raw-data-cst-pr117262-1.c17
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/raw-data-cst-pr117262-2.c36
6 files changed, 140 insertions, 6 deletions
diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
index 1fcf46a..dfce420 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -242,7 +242,12 @@ region_model_manager::get_or_create_constant_svalue (tree type, tree cst_expr)
const svalue *
region_model_manager::get_or_create_constant_svalue (tree cst_expr)
{
- return get_or_create_constant_svalue (TREE_TYPE (cst_expr), cst_expr);
+ tree type = TREE_TYPE (cst_expr);
+ if (TREE_CODE (cst_expr) == RAW_DATA_CST)
+ /* The type of a RAW_DATA_CST is the type of each element, rather than
+ that of the constant as a whole, so use NULL_TREE for simplicity. */
+ type = NULL_TREE;
+ return get_or_create_constant_svalue (type, cst_expr);
}
/* Return the svalue * for a constant_svalue for the INTEGER_CST
@@ -972,9 +977,10 @@ region_model_manager::maybe_fold_sub_svalue (tree type,
}
}
- /* Handle getting individual chars from a STRING_CST. */
+ /* Handle getting individual chars from a STRING_CST or RAW_DATA_CST. */
if (tree cst = parent_svalue->maybe_get_constant ())
- if (TREE_CODE (cst) == STRING_CST)
+ if (TREE_CODE (cst) == STRING_CST
+ || TREE_CODE (cst) == RAW_DATA_CST)
{
/* If we have a concrete 1-byte access within the parent region... */
byte_range subregion_bytes (0, 0);
@@ -982,13 +988,13 @@ region_model_manager::maybe_fold_sub_svalue (tree type,
&& subregion_bytes.m_size_in_bytes == 1
&& type)
{
- /* ...then attempt to get that char from the STRING_CST. */
+ /* ...then attempt to get that char from the constant. */
HOST_WIDE_INT hwi_start_byte
= subregion_bytes.m_start_byte_offset.to_shwi ();
tree cst_idx
= build_int_cst_type (size_type_node, hwi_start_byte);
if (const svalue *char_sval
- = maybe_get_char_from_string_cst (cst, cst_idx))
+ = maybe_get_char_from_cst (cst, cst_idx))
return get_or_create_cast (type, char_sval);
}
}
@@ -1505,6 +1511,24 @@ get_or_create_const_fn_result_svalue (tree type,
return const_fn_result_sval;
}
+/* Given DATA_CST (a STRING_CST or RAW_DATA_CST) and BYTE_OFFSET_CST a constant,
+ attempt to get the character at that offset, returning either
+ the svalue for the character constant, or NULL if unsuccessful. */
+
+const svalue *
+region_model_manager::maybe_get_char_from_cst (tree data_cst,
+ tree byte_offset_cst)
+{
+ switch (TREE_CODE (data_cst))
+ {
+ default: gcc_unreachable ();
+ case STRING_CST:
+ return maybe_get_char_from_string_cst (data_cst, byte_offset_cst);
+ case RAW_DATA_CST:
+ return maybe_get_char_from_raw_data_cst (data_cst, byte_offset_cst);
+ }
+}
+
/* Get a tree for the size of STRING_CST, or NULL_TREE.
Note that this may be larger than TREE_STRING_LENGTH (implying
a run of trailing zero bytes from TREE_STRING_LENGTH up to this
@@ -1558,6 +1582,25 @@ region_model_manager::maybe_get_char_from_string_cst (tree string_cst,
return NULL;
}
+/* Given RAW_DATA_CST, a RAW_DATA_CST and BYTE_OFFSET_CST a constant,
+ attempt to get the character at that offset, returning either
+ the svalue for the character constant, or NULL if unsuccessful. */
+
+const svalue *
+region_model_manager::maybe_get_char_from_raw_data_cst (tree raw_data_cst,
+ tree byte_offset_cst)
+{
+ gcc_assert (TREE_CODE (raw_data_cst) == RAW_DATA_CST);
+ gcc_assert (TREE_CODE (byte_offset_cst) == INTEGER_CST);
+
+ offset_int o = (wi::to_offset (byte_offset_cst));
+ if (o >= 0 && o < RAW_DATA_LENGTH (raw_data_cst))
+ return get_or_create_int_cst
+ (TREE_TYPE (raw_data_cst),
+ RAW_DATA_UCHAR_ELT (raw_data_cst, o.to_uhwi ()));
+ return nullptr;
+}
+
/* region consolidation. */
/* Return the region for FNDECL, creating it if necessary. */
diff --git a/gcc/analyzer/region-model-manager.h b/gcc/analyzer/region-model-manager.h
index c9c6523..c3f0a64 100644
--- a/gcc/analyzer/region-model-manager.h
+++ b/gcc/analyzer/region-model-manager.h
@@ -98,8 +98,12 @@ public:
tree fndecl,
const vec<const svalue *> &inputs);
+ const svalue *maybe_get_char_from_cst (tree data_cst,
+ tree byte_offset_cst);
const svalue *maybe_get_char_from_string_cst (tree string_cst,
tree byte_offset_cst);
+ const svalue *maybe_get_char_from_raw_data_cst (tree raw_data_cst,
+ tree byte_offset_cst);
/* Dynamically-allocated svalue instances.
The number of these within the analysis can grow arbitrarily.
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 79378a9..84b81e9 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -2801,6 +2801,7 @@ region_model::get_rvalue_1 (path_var pv, region_model_context *ctxt) const
case COMPLEX_CST:
case VECTOR_CST:
case STRING_CST:
+ case RAW_DATA_CST:
return m_mgr->get_or_create_constant_svalue (pv.m_tree);
case POINTER_PLUS_EXPR:
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index caae843..ab469dd 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -905,6 +905,37 @@ get_subregion_within_ctor (const region *parent_reg, tree index,
}
}
+/* Get the child region of PARENT_REG based upon (INDEX, VALUE) within a
+ CONSTRUCTOR. */
+
+static const region *
+get_subregion_within_ctor_for_ctor_pair (const region *parent_reg,
+ tree index,
+ tree value,
+ region_model_manager *mgr)
+{
+ if (TREE_CODE (index) == INTEGER_CST
+ && TREE_CODE (value) == RAW_DATA_CST)
+ {
+ /* Special-case; see tree.def's description of CONSTRUCTOR.
+ We have RAW_DATA_LENGTH of bytes, starting at INDEX's start. */
+ const region *start_reg
+ = get_subregion_within_ctor (parent_reg, index, mgr);
+ /* Build a bit range, relative to PARENT_REG. */
+ region_offset start_offset = start_reg->get_offset (mgr);
+
+ if (!start_offset.concrete_p ())
+ return nullptr;
+ bit_offset_t start_bit_offset = start_offset.get_bit_offset ();
+ int length = RAW_DATA_LENGTH (value);
+ bit_range bits (start_bit_offset, length * BITS_PER_UNIT);
+
+ return mgr->get_bit_range (parent_reg, NULL_TREE, bits);
+ }
+
+ return get_subregion_within_ctor (parent_reg, index, mgr);
+}
+
/* Get the svalue for VAL, a non-CONSTRUCTOR value within a CONSTRUCTOR. */
static const svalue *
@@ -1035,7 +1066,9 @@ binding_map::apply_ctor_pair_to_child_region (const region *parent_reg,
tree index, tree val)
{
const region *child_reg
- = get_subregion_within_ctor (parent_reg, index, mgr);
+ = get_subregion_within_ctor_for_ctor_pair (parent_reg, index, val, mgr);
+ if (!child_reg)
+ return false;
if (TREE_CODE (val) == CONSTRUCTOR)
return apply_ctor_to_region (child_reg, val, mgr);
else
diff --git a/gcc/testsuite/c-c++-common/analyzer/raw-data-cst-pr117262-1.c b/gcc/testsuite/c-c++-common/analyzer/raw-data-cst-pr117262-1.c
new file mode 100644
index 0000000..0c8d3e6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/analyzer/raw-data-cst-pr117262-1.c
@@ -0,0 +1,17 @@
+int
+main ()
+{
+ const unsigned char meow_bytes[] = {
+ 0x69, 0x6e, 0x74, 0x0a, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a,
+ 0x7b, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x75, 0x6e,
+ 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20,
+ 0x6d, 0x65, 0x6f, 0x77, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5b, 0x5d,
+ 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20,
+ 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x20, 0x6d,
+ };
+ short meow[sizeof (meow_bytes) / sizeof (short)] = {};
+ for (int i = 0; i < (int) (sizeof (meow) / sizeof (short)); i++)
+ meow[i] = (meow_bytes[i * 2] << 8) | meow_bytes[i * 2 + 1];
+ if (meow[0] != (0x69 << 8) + 0x6e)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/c-c++-common/analyzer/raw-data-cst-pr117262-2.c b/gcc/testsuite/c-c++-common/analyzer/raw-data-cst-pr117262-2.c
new file mode 100644
index 0000000..8d43efe
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/analyzer/raw-data-cst-pr117262-2.c
@@ -0,0 +1,36 @@
+#include "analyzer-decls.h"
+
+extern void use (unsigned char);
+
+void
+test ()
+{
+ const unsigned char meow_bytes[] = {
+ 0x69, 0x6e, 0x74, 0x0a, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a,
+ 0x7b, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x75, 0x6e,
+ 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20,
+ 0x6d, 0x65, 0x6f, 0x77, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5b, 0x5d,
+ 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20,
+ 0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x20, 0x6d,
+ };
+
+ /* Verify that analyzer "knows" the values of individual bytes in
+ the array. */
+
+ /* First row. */
+ __analyzer_eval (meow_bytes[0] == 0x69); /* { dg-warning "TRUE" } */
+ __analyzer_eval (meow_bytes[1] == 0x6e); /* { dg-warning "TRUE" } */
+ __analyzer_eval (meow_bytes[11] == 0x0a); /* { dg-warning "TRUE" } */
+
+ /* Second row. */
+ __analyzer_eval (meow_bytes[12] == 0x7b); /* { dg-warning "TRUE" } */
+ __analyzer_eval (meow_bytes[23] == 0x6e); /* { dg-warning "TRUE" } */
+
+ /* Final row. */
+ __analyzer_eval (meow_bytes[60] == 0x7d); /* { dg-warning "TRUE" } */
+ __analyzer_eval (meow_bytes[70] == 0x20); /* { dg-warning "TRUE" } */
+ __analyzer_eval (meow_bytes[71] == 0x6d); /* { dg-warning "TRUE" } */
+
+ use (meow_bytes[-1]); /* { dg-warning "stack-based buffer under-read" } */
+ use (meow_bytes[72]); /* { dg-warning "stack-based buffer over-read" } */
+}