+2020-03-27 David Malcolm <dmalcolm@redhat.com>
+
+ * program-state.cc (selftest::test_program_state_dumping): Update
+ expected dump to include symbolic_region's possibly_null field.
+ * region-model.cc (symbolic_region::print_fields): New vfunc
+ implementation.
+ (region_model::add_constraint): Clear m_possibly_null from
+ symbolic_regions now known to be non-NULL.
+ (selftest::test_malloc_constraints): New selftest.
+ (selftest::analyzer_region_model_cc_tests): Call it.
+ * region-model.h (region::dyn_cast_symbolic_region): Add non-const
+ overload.
+ (symbolic_region::dyn_cast_symbolic_region): Implement it.
+ (symbolic_region::print_fields): New vfunc override decl.
+
2020-03-27 David Malcolm <dmalcolm@redhat.com>
* analyzer.h (class feasibility_problem): New forward decl.
"rmodel: r0: {kind: `root', parent: null, sval: null}\n"
"|-heap: r1: {kind: `heap', parent: r0, sval: sv0}\n"
"| |: sval: sv0: {poisoned: uninit}\n"
- "| `-r2: {kind: `symbolic', parent: r1, sval: null}\n"
+ "| `-r2: {kind: `symbolic', parent: r1, sval: null, possibly_null: true}\n"
"`-globals: r3: {kind: `globals', parent: r0, sval: null, map: {`p': r4}}\n"
" `-`p': r4: {kind: `primitive', parent: r3, sval: sv1, type: `void *'}\n"
" |: sval: sv1: {type: `void *', &r2}\n"
/* Empty. */
}
+/* Implementation of region::print_fields vfunc for symbolic_region. */
+
+void
+symbolic_region::print_fields (const region_model &model,
+ region_id this_rid,
+ pretty_printer *pp) const
+{
+ region::print_fields (model, this_rid, pp);
+ pp_printf (pp, ", possibly_null: %s", m_possibly_null ? "true" : "false");
+}
+
/* class region_model. */
/* region_model's default ctor. */
add_any_constraints_from_ssa_def_stmt (lhs, op, rhs, ctxt);
+ /* If we now know a symbolic_region is non-NULL, clear its
+ m_possibly_null. */
+ if (zerop (rhs) && op == NE_EXPR)
+ if (region_svalue *ptr = get_svalue (lhs_sid)->dyn_cast_region_svalue ())
+ {
+ region *pointee = get_region (ptr->get_pointee ());
+ if (symbolic_region *sym_reg = pointee->dyn_cast_symbolic_region ())
+ sym_reg->m_possibly_null = false;
+ }
+
/* Notify the context, if any. This exists so that the state machines
in a program_state can be notified about the condition, and so can
set sm-state for e.g. unchecked->checked, both for cfg-edges, and
tristate (tristate::TS_UNKNOWN));
}
+/* Verify that if we mark a pointer to a malloc-ed region as non-NULL,
+ all cast pointers to that region are also known to be non-NULL. */
+
+static void
+test_malloc_constraints ()
+{
+ region_model model;
+ tree p = build_global_decl ("p", ptr_type_node);
+ tree char_star = build_pointer_type (char_type_node);
+ tree q = build_global_decl ("q", char_star);
+ tree null_ptr = build_int_cst (ptr_type_node, 0);
+
+ region_id rid = model.add_new_malloc_region ();
+ svalue_id sid = model.get_or_create_ptr_svalue (ptr_type_node, rid);
+ model.set_value (model.get_lvalue (p, NULL), sid, NULL);
+ model.set_value (q, p, NULL);
+
+ /* We should have a symbolic_region with m_possibly_null: true. */
+ region *pointee = model.get_region (rid);
+ symbolic_region *sym_reg = pointee->dyn_cast_symbolic_region ();
+ ASSERT_NE (sym_reg, NULL);
+ ASSERT_TRUE (sym_reg->m_possibly_null);
+
+ ASSERT_CONDITION_UNKNOWN (model, p, NE_EXPR, null_ptr);
+ ASSERT_CONDITION_UNKNOWN (model, p, EQ_EXPR, null_ptr);
+ ASSERT_CONDITION_UNKNOWN (model, q, NE_EXPR, null_ptr);
+ ASSERT_CONDITION_UNKNOWN (model, q, EQ_EXPR, null_ptr);
+
+ model.add_constraint (p, NE_EXPR, null_ptr, NULL);
+
+ /* Adding the constraint should have cleared m_possibly_null. */
+ ASSERT_FALSE (sym_reg->m_possibly_null);
+
+ ASSERT_CONDITION_TRUE (model, p, NE_EXPR, null_ptr);
+ ASSERT_CONDITION_FALSE (model, p, EQ_EXPR, null_ptr);
+ ASSERT_CONDITION_TRUE (model, q, NE_EXPR, null_ptr);
+ ASSERT_CONDITION_FALSE (model, q, EQ_EXPR, null_ptr);
+}
+
/* Run all of the selftests within this file. */
void
test_canonicalization_4 ();
test_state_merging ();
test_constraint_merging ();
+ test_malloc_constraints ();
}
} // namespace selftest
virtual enum region_kind get_kind () const = 0;
virtual map_region *dyn_cast_map_region () { return NULL; }
virtual array_region *dyn_cast_array_region () { return NULL; }
- virtual const symbolic_region *dyn_cast_symbolic_region () const
- { return NULL; }
+ virtual symbolic_region *dyn_cast_symbolic_region () { return NULL; }
+ virtual const symbolic_region *dyn_cast_symbolic_region () const { return NULL; }
region_id get_parent () const { return m_parent_rid; }
region *get_parent_region (const region_model &model) const;
const symbolic_region *dyn_cast_symbolic_region () const FINAL OVERRIDE
{ return this; }
+ symbolic_region *dyn_cast_symbolic_region () FINAL OVERRIDE
+ { return this; }
bool compare_fields (const symbolic_region &other) const;
void walk_for_canonicalization (canonicalization *c) const FINAL OVERRIDE;
+ void print_fields (const region_model &model,
+ region_id this_rid,
+ pretty_printer *pp) const FINAL OVERRIDE;
+
bool m_possibly_null;
};