From 31332e4d2641006341a5a4f8be2e81b69ee430d6 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Fri, 15 May 2020 06:20:33 -0400 Subject: [PATCH 134/179] FIXME: handle gassign of STRING_CST --- gcc/analyzer/region-model2.cc | 80 ++++++++++++++++++------- gcc/analyzer/store2.cc | 4 +- gcc/analyzer/store2.h | 2 +- gcc/testsuite/gcc.dg/analyzer/casts-1.c | 9 +++ 4 files changed, 69 insertions(+), 26 deletions(-) diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc index 9b725e626d4..2caf5e421ea 100644 --- a/gcc/analyzer/region-model2.cc +++ b/gcc/analyzer/region-model2.cc @@ -2788,6 +2788,32 @@ region_model2_manager::get_or_create_binop (tree type, enum tree_code op, /* FIXME. */ +static const svalue2 * +maybe_get_char_from_string_cst (tree string_cst, tree byte_offset_cst, + region_model2_manager *mgr) +{ + gcc_assert (TREE_CODE (string_cst) == STRING_CST); + + /* Adapted from fold_read_from_constant_string. */ + scalar_int_mode char_mode; + if (TREE_CODE (byte_offset_cst) == INTEGER_CST + && compare_tree_int (byte_offset_cst, + TREE_STRING_LENGTH (string_cst)) < 0 + && is_int_mode (TYPE_MODE (TREE_TYPE (TREE_TYPE (string_cst))), + &char_mode) + && GET_MODE_SIZE (char_mode) == 1) + { + tree char_cst + = build_int_cst_type (TREE_TYPE (TREE_TYPE (string_cst)), + (TREE_STRING_POINTER (string_cst) + [TREE_INT_CST_LOW (byte_offset_cst)])); + return mgr->get_or_create_constant_svalue2 (char_cst); + } + return NULL; +} + +/* FIXME. */ + const svalue2 * region_model2_manager::get_or_create_sub_svalue2 (tree type, const svalue2 *parent_svalue2, @@ -2803,12 +2829,23 @@ region_model2_manager::get_or_create_sub_svalue2 (tree type, { const svalue2 *cst_sval = get_or_create_constant_svalue2 (cst); - const svalue2 *cast_sval - = get_or_create_unaryop (type, NOP_EXPR, cst_sval); - return cast_sval; + return get_or_create_cast (type, cst_sval); } } + /* Handle getting individual chars from a STRING_CST. */ + if (tree cst = parent_svalue2->maybe_get_constant ()) + if (TREE_CODE (cst) == STRING_CST) + if (const element_region2 *element_reg + = subregion->dyn_cast_element_region2 ()) + { + const svalue2 *idx_sval = element_reg->get_index (); + if (tree cst_idx = idx_sval->maybe_get_constant ()) + if (const svalue2 *char_sval + = maybe_get_char_from_string_cst (cst, cst_idx, this)) + return get_or_create_cast (type, char_sval); + } + sub_svalue2::key_t key (type, parent_svalue2, subregion); if (sub_svalue2 **slot = m_sub_values_map.get (key)) return *slot; @@ -3779,6 +3816,17 @@ region_model2::on_gassign (const supernode */*snode*/, } break; + case STRING_CST: + { + /* e.g. "struct s2 x = {{'A', 'B', 'C', 'D'}};". */ + /* Add a default binding, rather than a direct one, so that array + access will "inherit" the individual chars. */ + const svalue2 *rhs_sval = get_rvalue (rhs1, ctxt); + m_store.set_value (m_mgr->get_store2_manager(), lhs_reg, rhs_sval, + BK_default); + } + break; + /* Assignments of the form set_value (lvalue (LHS), rvalue (EXPR)) for various EXPR. @@ -4840,8 +4888,6 @@ region_model2::get_lvalue_1 (path_var pv, return m_mgr->get_offset_region (star_ptr, TREE_TYPE (expr), offset_sval, ctxt); - /* TODO: a selftest of casting a buffer to both an (int *) - and a (coord *), and doing array accesses with both arrays. */ } break; @@ -5114,23 +5160,10 @@ region_model2::get_store_value (const region2 *reg) = reg->get_parent_region ()->dyn_cast_string_region2 ()) { tree string_cst = str_reg->get_string_cst (); - gcc_assert (TREE_CODE (string_cst) == STRING_CST); - - /* Adapted from fold_read_from_constant_string. */ - scalar_int_mode char_mode; - if (TREE_CODE (byte_offset_cst) == INTEGER_CST - && compare_tree_int (byte_offset_cst, - TREE_STRING_LENGTH (string_cst)) < 0 - && is_int_mode (TYPE_MODE (TREE_TYPE (TREE_TYPE (string_cst))), - &char_mode) - && GET_MODE_SIZE (char_mode) == 1) - { - tree char_cst - = build_int_cst_type (TREE_TYPE (TREE_TYPE (string_cst)), - (TREE_STRING_POINTER (string_cst) - [TREE_INT_CST_LOW (byte_offset_cst)])); - return m_mgr->get_or_create_constant_svalue2 (char_cst); - } + if (const svalue2 *char_sval + = maybe_get_char_from_string_cst (string_cst, byte_offset_cst, + m_mgr)) + return char_sval; } /* FIXME: symbolic value. */ @@ -5446,7 +5479,8 @@ region_model2::set_value (const region2 *lhs_reg, const svalue2 *rhs_sval, gcc_assert (lhs_reg); gcc_assert (rhs_sval); - m_store.set_value (m_mgr->get_store2_manager(), lhs_reg, rhs_sval); + m_store.set_value (m_mgr->get_store2_manager(), lhs_reg, rhs_sval, + BK_direct); } /* Set the value of the region2 given by LHS to the value given diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc index b6db23ffd6c..812ba8df038 100644 --- a/gcc/analyzer/store2.cc +++ b/gcc/analyzer/store2.cc @@ -833,13 +833,13 @@ store2::get_any_binding (store2_manager *mgr, const region2 *reg) void store2::set_value (store2_manager *mgr, const region2 *lhs_reg, - const svalue2 *rhs_sval) + const svalue2 *rhs_sval, enum binding_kind kind) { remove_overlapping_bindings (mgr, lhs_reg); const region2 *base_reg = lhs_reg->get_base_region (); binding_cluster2 *cluster = get_or_create_cluster (base_reg); - cluster->bind (mgr, lhs_reg, rhs_sval, BK_direct); + cluster->bind (mgr, lhs_reg, rhs_sval, kind); // TODO: various kinds of invalidation etc } diff --git a/gcc/analyzer/store2.h b/gcc/analyzer/store2.h index 952b274acc0..3ab0f80a0c6 100644 --- a/gcc/analyzer/store2.h +++ b/gcc/analyzer/store2.h @@ -292,7 +292,7 @@ public: const svalue2 *get_any_binding (store2_manager *mgr, const region2 *reg); void set_value (store2_manager *mgr, const region2 *lhs_reg, - const svalue2 *rhs_sval); + const svalue2 *rhs_sval, enum binding_kind kind); void clobber_region (store2_manager *mgr, const region2 *reg); void purge_region (store2_manager *mgr, const region2 *reg); void zero_fill_region (store2_manager *mgr, const region2 *reg); diff --git a/gcc/testsuite/gcc.dg/analyzer/casts-1.c b/gcc/testsuite/gcc.dg/analyzer/casts-1.c index 7c9fb56451c..39a0bb1fd06 100644 --- a/gcc/testsuite/gcc.dg/analyzer/casts-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/casts-1.c @@ -29,3 +29,12 @@ void test_1 () __analyzer_eval (((struct s2 *)&x)->arr[1] == '#'); /* { dg-warning "TRUE" } */ __analyzer_eval (x.b == '#'); /* { dg-warning "TRUE" } */ } + +void test_2 () +{ + struct s2 x = {{'A', 'B', 'C', 'D'}}; + __analyzer_eval (x.arr[0] == 'A'); /* { dg-warning "TRUE" } */ + __analyzer_eval (x.arr[1] == 'B'); /* { dg-warning "TRUE" } */ + __analyzer_eval (x.arr[2] == 'C'); /* { dg-warning "TRUE" } */ + __analyzer_eval (x.arr[3] == 'D'); /* { dg-warning "TRUE" } */ +} -- 2.21.0