(root)/
gcc-13.2.0/
gcc/
analyzer/
sm.cc
/* Modeling API uses and misuses via state machines.
   Copyright (C) 2019-2023 Free Software Foundation, Inc.
   Contributed by David Malcolm <dmalcolm@redhat.com>.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "function.h"
#include "basic-block.h"
#include "gimple.h"
#include "options.h"
#include "function.h"
#include "diagnostic-core.h"
#include "pretty-print.h"
#include "diagnostic.h"
#include "tree-diagnostic.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/svalue.h"
#include "analyzer/program-state.h"
#include "analyzer/pending-diagnostic.h"

#if ENABLE_ANALYZER

namespace ana {

/* Return true if VAR has pointer or reference type.  */

bool
any_pointer_p (tree var)
{
  return POINTER_TYPE_P (TREE_TYPE (var));
}

/* Return true if SVAL has pointer or reference type.  */

bool
any_pointer_p (const svalue *sval)
{
  if (!sval->get_type ())
    return false;
  return POINTER_TYPE_P (sval->get_type ());
}

/* class state_machine::state.  */

/* Base implementation of dump_to_pp vfunc.  */

void
state_machine::state::dump_to_pp (pretty_printer *pp) const
{
  pp_string (pp, m_name);
}

/* Return a new json::string describing the state.  */

json::value *
state_machine::state::to_json () const
{
  pretty_printer pp;
  pp_format_decoder (&pp) = default_tree_printer;
  dump_to_pp (&pp);
  return new json::string (pp_formatted_text (&pp));
}

/* class state_machine.  */

/* state_machine's ctor.  */

state_machine::state_machine (const char *name, logger *logger)
: log_user (logger), m_name (name), m_next_state_id (0),
  m_start (add_state ("start"))
{
}

/* Add a state with name NAME to this state_machine.
   The string is required to outlive the state_machine.

   Return the state_t for the new state.  */

state_machine::state_t
state_machine::add_state (const char *name)
{
  state *s = new state (name, alloc_state_id ());
  m_states.safe_push (s);
  return s;
}

/* Get the state with name NAME, which must exist.
   This is purely intended for use in selftests.  */

state_machine::state_t
state_machine::get_state_by_name (const char *name) const
{
  unsigned i;
  state *s;
  FOR_EACH_VEC_ELT (m_states, i, s)
    if (!strcmp (name, s->get_name ()))
      return s;
  /* Name not found.  */
  gcc_unreachable ();
}

/* Base implementation of state_machine::on_leak.  */

std::unique_ptr<pending_diagnostic>
state_machine::on_leak (tree var ATTRIBUTE_UNUSED) const
{
  return NULL;
}

/* Dump a multiline representation of this state machine to PP.  */

void
state_machine::dump_to_pp (pretty_printer *pp) const
{
  unsigned i;
  state *s;
  FOR_EACH_VEC_ELT (m_states, i, s)
    {
      pp_printf (pp, "  state %i: ", i);
      s->dump_to_pp (pp);
      pp_newline (pp);
    }
}

/* Return a new json::object of the form
   {"name" : str,
    "states" : [str]}.  */

json::object *
state_machine::to_json () const
{
  json::object *sm_obj = new json::object ();

  sm_obj->set ("name", new json::string (m_name));
  {
    json::array *states_arr = new json::array ();
    unsigned i;
    state *s;
    FOR_EACH_VEC_ELT (m_states, i, s)
      states_arr->append (s->to_json ());
    sm_obj->set ("states", states_arr);
  }

  return sm_obj;
}

/* class sm_context.  */

const region_model *
sm_context::get_old_region_model () const
{
  if (const program_state *old_state = get_old_program_state ())
    return old_state->m_region_model;
  else
    return NULL;
}

/* Create instances of the various state machines, each using LOGGER,
   and populate OUT with them.  */

void
make_checkers (auto_delete_vec <state_machine> &out, logger *logger)
{
  out.safe_push (make_malloc_state_machine (logger));
  out.safe_push (make_fileptr_state_machine (logger));
  out.safe_push (make_fd_state_machine (logger));
  /* The "taint" checker must be explicitly enabled (as it currently
     leads to state explosions that stop the other checkers working).  */
  if (flag_analyzer_checker)
    out.safe_push (make_taint_state_machine (logger));
  out.safe_push (make_sensitive_state_machine (logger));
  out.safe_push (make_signal_state_machine (logger));
  out.safe_push (make_va_list_state_machine (logger));

  /* We only attempt to run the pattern tests if it might have been manually
     enabled (for DejaGnu purposes).  */
  if (flag_analyzer_checker)
    out.safe_push (make_pattern_test_state_machine (logger));

  if (flag_analyzer_checker)
    {
      unsigned read_index, write_index;
      state_machine **sm;

      /* TODO: this leaks the machines
	 Would be nice to log the things that were removed.  */
      VEC_ORDERED_REMOVE_IF (out, read_index, write_index, sm,
			     0 != strcmp (flag_analyzer_checker,
					  (*sm)->get_name ()));
    }
}

} // namespace ana

#endif /* #if ENABLE_ANALYZER */