From ecdb93224c56189a129e97c556fe6b78e1b15a63 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 27 Aug 2020 18:20:24 -0400 Subject: [PATCH] analyzer: fix ICE on casting float to pointer [PR96764] gcc/analyzer/ChangeLog: PR analyzer/96764 * region-model-manager.cc (region_model_manager::maybe_fold_unaryop): Handle VIEW_CONVERT_EXPR. (region_model_manager::get_or_create_cast): Move logic for real->integer casting to... (get_code_for_cast): ...this new function, and add logic for real->non-integer casts. (region_model_manager::maybe_fold_sub_svalue): Handle VIEW_CONVERT_EXPR. * region-model.cc (region_model::add_any_constraints_from_gassign): Likewise. * svalue.cc (svalue::maybe_undo_cast): Likewise. (unaryop_svalue::dump_to_pp): Likewise. gcc/testsuite/ChangeLog: PR analyzer/96764 * gcc.dg/analyzer/pr96764.c: New test. --- gcc/analyzer/region-model-manager.cc | 35 +++++++++++++++++++++++++++------ gcc/analyzer/region-model.cc | 1 + gcc/analyzer/svalue.cc | 13 +++++++----- gcc/testsuite/gcc.dg/analyzer/pr96764.c | 6 ++++++ 4 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/analyzer/pr96764.c diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc index 9bfb081..da8fa01 100644 --- a/gcc/analyzer/region-model-manager.cc +++ b/gcc/analyzer/region-model-manager.cc @@ -324,6 +324,7 @@ region_model_manager::maybe_fold_unaryop (tree type, enum tree_code op, switch (op) { default: break; + case VIEW_CONVERT_EXPR: case NOP_EXPR: { /* Handle redundant casts. */ @@ -390,6 +391,30 @@ region_model_manager::get_or_create_unaryop (tree type, enum tree_code op, return unaryop_sval; } +/* Get a tree code for a cast to DST_TYPE from SRC_TYPE. + Use NOP_EXPR if possible (e.g. to help fold_unary convert casts + of 0 to (T*) to simple pointer constants), but use FIX_TRUNC_EXPR + and VIEW_CONVERT_EXPR for cases that fold_unary would otherwise crash + on. */ + +static enum tree_code +get_code_for_cast (tree dst_type, tree src_type) +{ + gcc_assert (dst_type); + if (!src_type) + return NOP_EXPR; + + if (TREE_CODE (src_type) == REAL_TYPE) + { + if (TREE_CODE (dst_type) == INTEGER_TYPE) + return FIX_TRUNC_EXPR; + else + return VIEW_CONVERT_EXPR; + } + + return NOP_EXPR; +} + /* Return the svalue * for a cast of ARG to type TYPE, creating it if necessary. */ @@ -397,11 +422,8 @@ const svalue * region_model_manager::get_or_create_cast (tree type, const svalue *arg) { gcc_assert (type); - if (arg->get_type ()) - if (TREE_CODE (type) == INTEGER_TYPE - && TREE_CODE (arg->get_type ()) == REAL_TYPE) - return get_or_create_unaryop (type, FIX_TRUNC_EXPR, arg); - return get_or_create_unaryop (type, NOP_EXPR, arg); + enum tree_code op = get_code_for_cast (type, arg->get_type ()); + return get_or_create_unaryop (type, op, arg); } /* Subroutine of region_model_manager::get_or_create_binop. @@ -561,7 +583,8 @@ region_model_manager::maybe_fold_sub_svalue (tree type, if (const unaryop_svalue *unary = parent_svalue->dyn_cast_unaryop_svalue ()) { - if (unary->get_op () == NOP_EXPR) + if (unary->get_op () == NOP_EXPR + || unary->get_op () == VIEW_CONVERT_EXPR) if (tree cst = unary->get_arg ()->maybe_get_constant ()) if (zerop (cst)) { diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 02bbfa5..1f794da 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -1764,6 +1764,7 @@ region_model::add_any_constraints_from_gassign (enum tree_code op, break; case NOP_EXPR: + case VIEW_CONVERT_EXPR: { add_constraint (gimple_assign_rhs1 (assign), op, rhs, ctxt); } diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc index a1c6241..fcab578 100644 --- a/gcc/analyzer/svalue.cc +++ b/gcc/analyzer/svalue.cc @@ -128,16 +128,19 @@ svalue::maybe_get_constant () const return NULL_TREE; } -/* If this svalue is a cast (i.e a unaryop NOP_EXPR), return the underlying - svalue. +/* If this svalue is a cast (i.e a unaryop NOP_EXPR or VIEW_CONVERT_EXPR), + return the underlying svalue. Otherwise return NULL. */ const svalue * svalue::maybe_undo_cast () const { if (const unaryop_svalue *unaryop_sval = dyn_cast_unaryop_svalue ()) - if (unaryop_sval->get_op () == NOP_EXPR) - return unaryop_sval->get_arg (); + { + enum tree_code op = unaryop_sval->get_op (); + if (op == NOP_EXPR || op == VIEW_CONVERT_EXPR) + return unaryop_sval->get_arg (); + } return NULL; } @@ -566,7 +569,7 @@ unaryop_svalue::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) { - if (m_op == NOP_EXPR) + if (m_op == VIEW_CONVERT_EXPR || m_op == NOP_EXPR) { pp_string (pp, "CAST("); dump_tree (pp, get_type ()); diff --git a/gcc/testsuite/gcc.dg/analyzer/pr96764.c b/gcc/testsuite/gcc.dg/analyzer/pr96764.c new file mode 100644 index 0000000..70b25d3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/pr96764.c @@ -0,0 +1,6 @@ +void +ar (int *hd) +{ + int **zv = &hd; + *(double *) zv = 0.0; +} -- 2.7.4