Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r15-8016-g8015a72ae49640.

gcc/analyzer/ChangeLog:
        PR analyzer/117262
        * region-model-manager.cc
        (region_model_manager::get_or_create_constant_svalue): Use
        NULL_TREE for the types of constant_svalue for RAW_DATA_CST.
        (region_model_manager::maybe_fold_sub_svalue): Generalize
        STRING_CST logic to also handle RAW_DATA_CST.
        (region_model_manager::maybe_get_char_from_cst): New.
        (region_model_manager::maybe_get_char_from_raw_data_cst): New.
        * region-model-manager.h
        (region_model_manager::maybe_get_char_from_cst): New decl.
        (region_model_manager::maybe_get_char_from_raw_data_cst): New decl.
        * region-model.cc (region_model::get_rvalue_1): Handle
        RAW_DATA_CST.
        * store.cc (get_subregion_within_ctor_for_ctor_pair): New.
        (binding_map::apply_ctor_pair_to_child_region): Call
        get_subregion_within_ctor_for_ctor_pair so that we handle
        RAW_DATA_CST.

gcc/testsuite/ChangeLog:
        PR analyzer/117262
        * c-c++-common/analyzer/raw-data-cst-pr117262-1.c: New test.
        * c-c++-common/analyzer/raw-data-cst-pr117262-2.c: New test.
---
 gcc/analyzer/region-model-manager.cc          | 53 +++++++++++++++++--
 gcc/analyzer/region-model-manager.h           |  4 ++
 gcc/analyzer/region-model.cc                  |  1 +
 gcc/analyzer/store.cc                         | 35 +++++++++++-
 .../analyzer/raw-data-cst-pr117262-1.c        | 17 ++++++
 .../analyzer/raw-data-cst-pr117262-2.c        | 36 +++++++++++++
 6 files changed, 140 insertions(+), 6 deletions(-)
 create mode 100644 
gcc/testsuite/c-c++-common/analyzer/raw-data-cst-pr117262-1.c
 create mode 100644 
gcc/testsuite/c-c++-common/analyzer/raw-data-cst-pr117262-2.c

diff --git a/gcc/analyzer/region-model-manager.cc 
b/gcc/analyzer/region-model-manager.cc
index 1fcf46aa619e..dfce420065d4 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 c9c6523685e1..c3f0a645a201 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 79378a9e6e5f..84b81e968002 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 caae843fb4b8..ab469dd0bca7 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 000000000000..0c8d3e6a5085
--- /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 000000000000..8d43efe32556
--- /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" } */
+}
-- 
2.26.3

Reply via email to