From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2209) id 1A574385E007; Fri, 16 Jul 2021 19:48:51 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1A574385E007 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: David Malcolm To: gcc-cvs@gcc.gnu.org Subject: [gcc r12-2375] analyzer: add __analyzer_dump_state X-Act-Checkin: gcc X-Git-Author: David Malcolm X-Git-Refname: refs/heads/master X-Git-Oldrev: 5932dd35eaa816e8d9b6406c6c433395ff5b6162 X-Git-Newrev: 9ea10c480565fa42b1804fb436f7e26ca77b71a3 Message-Id: <20210716194851.1A574385E007@sourceware.org> Date: Fri, 16 Jul 2021 19:48:51 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 16 Jul 2021 19:48:51 -0000 https://gcc.gnu.org/g:9ea10c480565fa42b1804fb436f7e26ca77b71a3 commit r12-2375-g9ea10c480565fa42b1804fb436f7e26ca77b71a3 Author: David Malcolm Date: Fri Jul 16 15:47:06 2021 -0400 analyzer: add __analyzer_dump_state gcc/analyzer/ChangeLog: * engine.cc (exploded_node::on_stmt_pre): Handle __analyzer_dump_state. * program-state.cc (extrinsic_state::get_sm_idx_by_name): New. (program_state::impl_call_analyzer_dump_state): New. * program-state.h (extrinsic_state::get_sm_idx_by_name): New decl. (program_state::impl_call_analyzer_dump_state): New decl. * region-model-impl-calls.cc (call_details::get_arg_string_literal): New. * region-model.h (call_details::get_arg_string_literal): New decl. gcc/ChangeLog: * doc/analyzer.texi: Add __analyzer_dump_state. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/analyzer-decls.h (__analyzer_dump_state): New. * gcc.dg/analyzer/dump-state.c: New test. Signed-off-by: David Malcolm Diff: --- gcc/analyzer/engine.cc | 3 ++ gcc/analyzer/program-state.cc | 49 ++++++++++++++++++++++++++ gcc/analyzer/program-state.h | 6 ++++ gcc/analyzer/region-model-impl-calls.cc | 18 ++++++++++ gcc/analyzer/region-model.h | 1 + gcc/doc/analyzer.texi | 9 +++++ gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h | 5 +++ gcc/testsuite/gcc.dg/analyzer/dump-state.c | 14 ++++++++ 8 files changed, 105 insertions(+) diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 7662a7f7bab..f9fc58180b7 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -1270,6 +1270,9 @@ exploded_node::on_stmt_pre (exploded_graph &eg, state->dump (eg.get_ext_state (), true); return; } + else if (is_special_named_call_p (call, "__analyzer_dump_state", 2)) + state->impl_call_analyzer_dump_state (call, eg.get_ext_state (), + ctxt); else if (is_setjmp_call_p (call)) { state->m_region_model->on_setjmp (call, this, ctxt); diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index cc53aef552f..30812176bd8 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -131,6 +131,27 @@ extrinsic_state::get_model_manager () const return NULL; /* for selftests. */ } +/* Try to find a state machine named NAME. + If found, return true and write its index to *OUT. + Otherwise return false. */ + +bool +extrinsic_state::get_sm_idx_by_name (const char *name, unsigned *out) const +{ + unsigned i; + state_machine *sm; + FOR_EACH_VEC_ELT (m_checkers, i, sm) + if (0 == strcmp (name, sm->get_name ())) + { + /* Found NAME. */ + *out = i; + return true; + } + + /* NAME not found. */ + return false; +} + /* struct sm_state_map::entry_t. */ int @@ -1290,6 +1311,34 @@ program_state::detect_leaks (const program_state &src_state, dest_state.m_region_model->unset_dynamic_extents (reg); } +/* Handle calls to "__analyzer_dump_state". */ + +void +program_state::impl_call_analyzer_dump_state (const gcall *call, + const extrinsic_state &ext_state, + region_model_context *ctxt) +{ + call_details cd (call, m_region_model, ctxt); + const char *sm_name = cd.get_arg_string_literal (0); + if (!sm_name) + { + error_at (call->location, "cannot determine state machine"); + return; + } + unsigned sm_idx; + if (!ext_state.get_sm_idx_by_name (sm_name, &sm_idx)) + { + error_at (call->location, "unrecognized state machine %qs", sm_name); + return; + } + const sm_state_map *smap = m_checker_states[sm_idx]; + + const svalue *sval = cd.get_arg_svalue (1); + + state_machine::state_t state = smap->get_state (sval, ext_state); + warning_at (call->location, 0, "state: %qs", state->get_name ()); +} + #if CHECKING_P namespace selftest { diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h index f16fe6ba984..8dee930665c 100644 --- a/gcc/analyzer/program-state.h +++ b/gcc/analyzer/program-state.h @@ -58,6 +58,8 @@ public: engine *get_engine () const { return m_engine; } region_model_manager *get_model_manager () const; + bool get_sm_idx_by_name (const char *name, unsigned *out) const; + private: /* The state machines. */ auto_delete_vec &m_checkers; @@ -256,6 +258,10 @@ public: const extrinsic_state &ext_state, region_model_context *ctxt); + void impl_call_analyzer_dump_state (const gcall *call, + const extrinsic_state &ext_state, + region_model_context *ctxt); + /* TODO: lose the pointer here (const-correctness issues?). */ region_model *m_region_model; auto_delete_vec m_checker_states; diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc index efb0fc83433..545634b9dc7 100644 --- a/gcc/analyzer/region-model-impl-calls.cc +++ b/gcc/analyzer/region-model-impl-calls.cc @@ -140,6 +140,24 @@ call_details::get_arg_svalue (unsigned idx) const return m_model->get_rvalue (arg, m_ctxt); } +/* Attempt to get the string literal for argument IDX, or return NULL + otherwise. + For use when implementing "__analyzer_*" functions that take + string literals. */ + +const char * +call_details::get_arg_string_literal (unsigned idx) const +{ + const svalue *str_arg = get_arg_svalue (idx); + if (const region *pointee = str_arg->maybe_get_region ()) + if (const string_region *string_reg = pointee->dyn_cast_string_region ()) + { + tree string_cst = string_reg->get_string_cst (); + return TREE_STRING_POINTER (string_cst); + } + return NULL; +} + /* Dump a multiline representation of this call to PP. */ void diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 71f6b3ee11e..f07a287f681 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -468,6 +468,7 @@ public: tree get_arg_tree (unsigned idx) const; tree get_arg_type (unsigned idx) const; const svalue *get_arg_svalue (unsigned idx) const; + const char *get_arg_string_literal (unsigned idx) const; void dump_to_pp (pretty_printer *pp, bool simple) const; void dump (bool simple) const; diff --git a/gcc/doc/analyzer.texi b/gcc/doc/analyzer.texi index 2ca4bf61352..aadb0de0798 100644 --- a/gcc/doc/analyzer.texi +++ b/gcc/doc/analyzer.texi @@ -521,6 +521,15 @@ it will also dump all of the states within the ``processed'' nodes. @end smallexample will dump the region_model's state to stderr. +@smallexample +__analyzer_dump_state ("malloc", ptr); +@end smallexample + +will emit a warning describing the state of the 2nd argument +(which can be of any type) with respect to the state machine with +a name matching the 1st argument (which must be a string literal). +This is for use when debugging, and may be of use in DejaGnu tests. + @smallexample __analyzer_eval (expr); @end smallexample diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h b/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h index 24466939882..e8745c0933f 100644 --- a/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h +++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-decls.h @@ -35,6 +35,11 @@ extern void __analyzer_dump_path (void); /* Dump the region_model's state to stderr. */ extern void __analyzer_dump_region_model (void); +/* Emit a warning describing the state of the 2nd argument + (which can be of any type) with respect to NAME. + This is for use when debugging, and may be of use in DejaGnu tests. */ +extern void __analyzer_dump_state (const char *name, ...); + /* Emit a warning with text "TRUE", FALSE" or "UNKNOWN" based on the truthfulness of the argument. */ extern void __analyzer_eval (int); diff --git a/gcc/testsuite/gcc.dg/analyzer/dump-state.c b/gcc/testsuite/gcc.dg/analyzer/dump-state.c new file mode 100644 index 00000000000..618a5a9d781 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/dump-state.c @@ -0,0 +1,14 @@ +/* Verify that __analyzer_dump_state works as expected. */ + +#include +#include "analyzer-decls.h" + +void test_1 (void) +{ + void *p = malloc (1024); + __analyzer_dump_state ("malloc", p); /* { dg-warning "state: 'unchecked'" } */ + free (p); + __analyzer_dump_state ("malloc", p); /* { dg-warning "state: 'freed'" } */ + __analyzer_dump_state (NULL, p); /* { dg-error "cannot determine state machine" } */ + __analyzer_dump_state ("not a state machine", p); /* { dg-error "unrecognized state machine 'not a state machine'" } */ +}