diff options
-rw-r--r-- | gcc/analyzer/region-model-manager.cc | 53 | ||||
-rw-r--r-- | gcc/analyzer/region-model-manager.h | 4 | ||||
-rw-r--r-- | gcc/analyzer/region-model.cc | 1 | ||||
-rw-r--r-- | gcc/analyzer/store.cc | 35 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/analyzer/raw-data-cst-pr117262-1.c | 17 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/analyzer/raw-data-cst-pr117262-2.c | 36 |
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" } */ +} |