analyzer: split out checker_event classes to their own header
gcc/analyzer/ChangeLog: * checker-path.h: Split out checker_event and its subclasses to... * checker-event.h: ...this new header. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
parent
12c583a2a3
commit
65752c1f7c
2 changed files with 612 additions and 582 deletions
610
gcc/analyzer/checker-event.h
Normal file
610
gcc/analyzer/checker-event.h
Normal file
|
@ -0,0 +1,610 @@
|
|||
/* Subclasses of diagnostic_event for analyzer diagnostics.
|
||||
Copyright (C) 2019-2022 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/>. */
|
||||
|
||||
#ifndef GCC_ANALYZER_CHECKER_EVENT_H
|
||||
#define GCC_ANALYZER_CHECKER_EVENT_H
|
||||
|
||||
#include "tree-logical-location.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* An enum for discriminating between the concrete subclasses of
|
||||
checker_event. */
|
||||
|
||||
enum event_kind
|
||||
{
|
||||
EK_DEBUG,
|
||||
EK_CUSTOM,
|
||||
EK_STMT,
|
||||
EK_REGION_CREATION,
|
||||
EK_FUNCTION_ENTRY,
|
||||
EK_STATE_CHANGE,
|
||||
EK_START_CFG_EDGE,
|
||||
EK_END_CFG_EDGE,
|
||||
EK_CALL_EDGE,
|
||||
EK_RETURN_EDGE,
|
||||
EK_START_CONSOLIDATED_CFG_EDGES,
|
||||
EK_END_CONSOLIDATED_CFG_EDGES,
|
||||
EK_INLINED_CALL,
|
||||
EK_SETJMP,
|
||||
EK_REWIND_FROM_LONGJMP,
|
||||
EK_REWIND_TO_SETJMP,
|
||||
EK_WARNING
|
||||
};
|
||||
|
||||
extern const char *event_kind_to_string (enum event_kind ek);
|
||||
|
||||
/* Event subclasses.
|
||||
|
||||
The class hierarchy looks like this (using indentation to show
|
||||
inheritance, and with event_kinds shown for the concrete subclasses):
|
||||
|
||||
diagnostic_event
|
||||
checker_event
|
||||
debug_event (EK_DEBUG)
|
||||
custom_event (EK_CUSTOM)
|
||||
precanned_custom_event
|
||||
statement_event (EK_STMT)
|
||||
region_creation_event (EK_REGION_CREATION)
|
||||
function_entry_event (EK_FUNCTION_ENTRY)
|
||||
state_change_event (EK_STATE_CHANGE)
|
||||
superedge_event
|
||||
cfg_edge_event
|
||||
start_cfg_edge_event (EK_START_CFG_EDGE)
|
||||
end_cfg_edge_event (EK_END_CFG_EDGE)
|
||||
call_event (EK_CALL_EDGE)
|
||||
return_edge (EK_RETURN_EDGE)
|
||||
start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES)
|
||||
end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES)
|
||||
inlined_call_event (EK_INLINED_CALL)
|
||||
setjmp_event (EK_SETJMP)
|
||||
rewind_event
|
||||
rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
|
||||
rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
|
||||
warning_event (EK_WARNING). */
|
||||
|
||||
/* Abstract subclass of diagnostic_event; the base class for use in
|
||||
checker_path (the analyzer's diagnostic_path subclass). */
|
||||
|
||||
class checker_event : public diagnostic_event
|
||||
{
|
||||
public:
|
||||
/* Implementation of diagnostic_event. */
|
||||
|
||||
location_t get_location () const final override { return m_loc; }
|
||||
tree get_fndecl () const final override { return m_effective_fndecl; }
|
||||
int get_stack_depth () const final override { return m_effective_depth; }
|
||||
const logical_location *get_logical_location () const final override
|
||||
{
|
||||
if (m_effective_fndecl)
|
||||
return &m_logical_loc;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
meaning get_meaning () const override;
|
||||
|
||||
/* Additional functionality. */
|
||||
|
||||
int get_original_stack_depth () const { return m_original_depth; }
|
||||
|
||||
virtual void prepare_for_emission (checker_path *,
|
||||
pending_diagnostic *pd,
|
||||
diagnostic_event_id_t emission_id);
|
||||
virtual bool is_call_p () const { return false; }
|
||||
virtual bool is_function_entry_p () const { return false; }
|
||||
virtual bool is_return_p () const { return false; }
|
||||
|
||||
/* For use with %@. */
|
||||
const diagnostic_event_id_t *get_id_ptr () const
|
||||
{
|
||||
return &m_emission_id;
|
||||
}
|
||||
|
||||
void dump (pretty_printer *pp) const;
|
||||
void debug () const;
|
||||
|
||||
void set_location (location_t loc) { m_loc = loc; }
|
||||
|
||||
protected:
|
||||
checker_event (enum event_kind kind,
|
||||
location_t loc, tree fndecl, int depth);
|
||||
|
||||
public:
|
||||
const enum event_kind m_kind;
|
||||
protected:
|
||||
location_t m_loc;
|
||||
tree m_original_fndecl;
|
||||
tree m_effective_fndecl;
|
||||
int m_original_depth;
|
||||
int m_effective_depth;
|
||||
pending_diagnostic *m_pending_diagnostic;
|
||||
diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
|
||||
tree_logical_location m_logical_loc;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for a purely textual event, for use in
|
||||
debugging path creation and filtering. */
|
||||
|
||||
class debug_event : public checker_event
|
||||
{
|
||||
public:
|
||||
debug_event (location_t loc, tree fndecl, int depth,
|
||||
const char *desc)
|
||||
: checker_event (EK_DEBUG, loc, fndecl, depth),
|
||||
m_desc (xstrdup (desc))
|
||||
{
|
||||
}
|
||||
~debug_event ()
|
||||
{
|
||||
free (m_desc);
|
||||
}
|
||||
|
||||
label_text get_desc (bool) const final override;
|
||||
|
||||
private:
|
||||
char *m_desc;
|
||||
};
|
||||
|
||||
/* An abstract event subclass for custom events. These are not filtered,
|
||||
as they are likely to be pertinent to the diagnostic. */
|
||||
|
||||
class custom_event : public checker_event
|
||||
{
|
||||
protected:
|
||||
custom_event (location_t loc, tree fndecl, int depth)
|
||||
: checker_event (EK_CUSTOM, loc, fndecl, depth)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/* A concrete custom_event subclass with a precanned message. */
|
||||
|
||||
class precanned_custom_event : public custom_event
|
||||
{
|
||||
public:
|
||||
precanned_custom_event (location_t loc, tree fndecl, int depth,
|
||||
const char *desc)
|
||||
: custom_event (loc, fndecl, depth),
|
||||
m_desc (xstrdup (desc))
|
||||
{
|
||||
}
|
||||
~precanned_custom_event ()
|
||||
{
|
||||
free (m_desc);
|
||||
}
|
||||
|
||||
label_text get_desc (bool) const final override;
|
||||
|
||||
private:
|
||||
char *m_desc;
|
||||
};
|
||||
|
||||
/* A concrete event subclass describing the execution of a gimple statement,
|
||||
for use at high verbosity levels when debugging paths. */
|
||||
|
||||
class statement_event : public checker_event
|
||||
{
|
||||
public:
|
||||
statement_event (const gimple *stmt, tree fndecl, int depth,
|
||||
const program_state &dst_state);
|
||||
|
||||
label_text get_desc (bool) const final override;
|
||||
|
||||
const gimple * const m_stmt;
|
||||
const program_state m_dst_state;
|
||||
};
|
||||
|
||||
/* There are too many combinations to express region creation in one message,
|
||||
so we emit multiple region_creation_event instances when each pertinent
|
||||
region is created.
|
||||
|
||||
This enum distinguishes between the different messages. */
|
||||
|
||||
enum rce_kind
|
||||
{
|
||||
/* Generate a message based on the memory space of the region
|
||||
e.g. "region created on stack here". */
|
||||
RCE_MEM_SPACE,
|
||||
|
||||
/* Generate a message based on the capacity of the region
|
||||
e.g. "capacity: 100 bytes". */
|
||||
RCE_CAPACITY,
|
||||
|
||||
/* Generate a debug message. */
|
||||
RCE_DEBUG
|
||||
};
|
||||
|
||||
/* A concrete event subclass describing the creation of a region that
|
||||
is significant for a diagnostic. */
|
||||
|
||||
class region_creation_event : public checker_event
|
||||
{
|
||||
public:
|
||||
region_creation_event (const region *reg,
|
||||
tree capacity,
|
||||
enum rce_kind kind,
|
||||
location_t loc, tree fndecl, int depth);
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
private:
|
||||
const region *m_reg;
|
||||
tree m_capacity;
|
||||
enum rce_kind m_rce_kind;
|
||||
};
|
||||
|
||||
/* An event subclass describing the entry to a function. */
|
||||
|
||||
class function_entry_event : public checker_event
|
||||
{
|
||||
public:
|
||||
function_entry_event (location_t loc, tree fndecl, int depth)
|
||||
: checker_event (EK_FUNCTION_ENTRY, loc, fndecl, depth)
|
||||
{
|
||||
}
|
||||
|
||||
function_entry_event (const program_point &dst_point);
|
||||
|
||||
label_text get_desc (bool can_colorize) const override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
bool is_function_entry_p () const final override { return true; }
|
||||
};
|
||||
|
||||
/* Subclass of checker_event describing a state change. */
|
||||
|
||||
class state_change_event : public checker_event
|
||||
{
|
||||
public:
|
||||
state_change_event (const supernode *node, const gimple *stmt,
|
||||
int stack_depth,
|
||||
const state_machine &sm,
|
||||
const svalue *sval,
|
||||
state_machine::state_t from,
|
||||
state_machine::state_t to,
|
||||
const svalue *origin,
|
||||
const program_state &dst_state);
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
function *get_dest_function () const
|
||||
{
|
||||
return m_dst_state.get_current_function ();
|
||||
}
|
||||
|
||||
const supernode *m_node;
|
||||
const gimple *m_stmt;
|
||||
const state_machine &m_sm;
|
||||
const svalue *m_sval;
|
||||
state_machine::state_t m_from;
|
||||
state_machine::state_t m_to;
|
||||
const svalue *m_origin;
|
||||
program_state m_dst_state;
|
||||
};
|
||||
|
||||
/* Subclass of checker_event; parent class for subclasses that relate to
|
||||
a superedge. */
|
||||
|
||||
class superedge_event : public checker_event
|
||||
{
|
||||
public:
|
||||
/* Mark this edge event as being either an interprocedural call or
|
||||
return in which VAR is in STATE, and that this is critical to the
|
||||
diagnostic (so that get_desc can attempt to get a better description
|
||||
from any pending_diagnostic). */
|
||||
void record_critical_state (tree var, state_machine::state_t state)
|
||||
{
|
||||
m_var = var;
|
||||
m_critical_state = state;
|
||||
}
|
||||
|
||||
const callgraph_superedge& get_callgraph_superedge () const;
|
||||
|
||||
bool should_filter_p (int verbosity) const;
|
||||
|
||||
protected:
|
||||
superedge_event (enum event_kind kind, const exploded_edge &eedge,
|
||||
location_t loc, tree fndecl, int depth);
|
||||
|
||||
public:
|
||||
const exploded_edge &m_eedge;
|
||||
const superedge *m_sedge;
|
||||
tree m_var;
|
||||
state_machine::state_t m_critical_state;
|
||||
};
|
||||
|
||||
/* An abstract event subclass for when a CFG edge is followed; it has two
|
||||
subclasses, representing the start of the edge and the end of the
|
||||
edge, which come in pairs. */
|
||||
|
||||
class cfg_edge_event : public superedge_event
|
||||
{
|
||||
public:
|
||||
meaning get_meaning () const override;
|
||||
|
||||
const cfg_superedge& get_cfg_superedge () const;
|
||||
|
||||
protected:
|
||||
cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
|
||||
location_t loc, tree fndecl, int depth);
|
||||
};
|
||||
|
||||
/* A concrete event subclass for the start of a CFG edge
|
||||
e.g. "following 'false' branch...'. */
|
||||
|
||||
class start_cfg_edge_event : public cfg_edge_event
|
||||
{
|
||||
public:
|
||||
start_cfg_edge_event (const exploded_edge &eedge,
|
||||
location_t loc, tree fndecl, int depth)
|
||||
: cfg_edge_event (EK_START_CFG_EDGE, eedge, loc, fndecl, depth)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
private:
|
||||
label_text maybe_describe_condition (bool can_colorize) const;
|
||||
|
||||
static label_text maybe_describe_condition (bool can_colorize,
|
||||
tree lhs,
|
||||
enum tree_code op,
|
||||
tree rhs);
|
||||
static bool should_print_expr_p (tree);
|
||||
};
|
||||
|
||||
/* A concrete event subclass for the end of a CFG edge
|
||||
e.g. "...to here'. */
|
||||
|
||||
class end_cfg_edge_event : public cfg_edge_event
|
||||
{
|
||||
public:
|
||||
end_cfg_edge_event (const exploded_edge &eedge,
|
||||
location_t loc, tree fndecl, int depth)
|
||||
: cfg_edge_event (EK_END_CFG_EDGE, eedge, loc, fndecl, depth)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool /*can_colorize*/) const final override
|
||||
{
|
||||
return label_text::borrow ("...to here");
|
||||
}
|
||||
};
|
||||
|
||||
/* A concrete event subclass for an interprocedural call. */
|
||||
|
||||
class call_event : public superedge_event
|
||||
{
|
||||
public:
|
||||
call_event (const exploded_edge &eedge,
|
||||
location_t loc, tree fndecl, int depth);
|
||||
|
||||
label_text get_desc (bool can_colorize) const override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
bool is_call_p () const final override;
|
||||
|
||||
protected:
|
||||
tree get_caller_fndecl () const;
|
||||
tree get_callee_fndecl () const;
|
||||
|
||||
const supernode *m_src_snode;
|
||||
const supernode *m_dest_snode;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for an interprocedural return. */
|
||||
|
||||
class return_event : public superedge_event
|
||||
{
|
||||
public:
|
||||
return_event (const exploded_edge &eedge,
|
||||
location_t loc, tree fndecl, int depth);
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
bool is_return_p () const final override;
|
||||
|
||||
const supernode *m_src_snode;
|
||||
const supernode *m_dest_snode;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for the start of a consolidated run of CFG
|
||||
edges all either TRUE or FALSE e.g. "following 'false' branch...'. */
|
||||
|
||||
class start_consolidated_cfg_edges_event : public checker_event
|
||||
{
|
||||
public:
|
||||
start_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth,
|
||||
bool edge_sense)
|
||||
: checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth),
|
||||
m_edge_sense (edge_sense)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
private:
|
||||
bool m_edge_sense;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for the end of a consolidated run of
|
||||
CFG edges e.g. "...to here'. */
|
||||
|
||||
class end_consolidated_cfg_edges_event : public checker_event
|
||||
{
|
||||
public:
|
||||
end_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth)
|
||||
: checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool /*can_colorize*/) const final override
|
||||
{
|
||||
return label_text::borrow ("...to here");
|
||||
}
|
||||
};
|
||||
|
||||
/* A concrete event subclass for describing an inlined call event
|
||||
e.g. "inlined call to 'callee' from 'caller'". */
|
||||
|
||||
class inlined_call_event : public checker_event
|
||||
{
|
||||
public:
|
||||
inlined_call_event (location_t loc,
|
||||
tree apparent_callee_fndecl,
|
||||
tree apparent_caller_fndecl,
|
||||
int actual_depth,
|
||||
int stack_depth_adjustment)
|
||||
: checker_event (EK_INLINED_CALL, loc,
|
||||
apparent_caller_fndecl,
|
||||
actual_depth + stack_depth_adjustment),
|
||||
m_apparent_callee_fndecl (apparent_callee_fndecl),
|
||||
m_apparent_caller_fndecl (apparent_caller_fndecl)
|
||||
{
|
||||
gcc_assert (LOCATION_BLOCK (loc) == NULL);
|
||||
}
|
||||
|
||||
label_text get_desc (bool /*can_colorize*/) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
private:
|
||||
tree m_apparent_callee_fndecl;
|
||||
tree m_apparent_caller_fndecl;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for a setjmp or sigsetjmp call. */
|
||||
|
||||
class setjmp_event : public checker_event
|
||||
{
|
||||
public:
|
||||
setjmp_event (location_t loc, const exploded_node *enode,
|
||||
tree fndecl, int depth, const gcall *setjmp_call)
|
||||
: checker_event (EK_SETJMP, loc, fndecl, depth),
|
||||
m_enode (enode), m_setjmp_call (setjmp_call)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
void prepare_for_emission (checker_path *path,
|
||||
pending_diagnostic *pd,
|
||||
diagnostic_event_id_t emission_id) final override;
|
||||
|
||||
private:
|
||||
const exploded_node *m_enode;
|
||||
const gcall *m_setjmp_call;
|
||||
};
|
||||
|
||||
/* An abstract event subclass for rewinding from a longjmp to a setjmp
|
||||
(or siglongjmp to sigsetjmp).
|
||||
|
||||
Base class for two from/to subclasses, showing the two halves of the
|
||||
rewind. */
|
||||
|
||||
class rewind_event : public checker_event
|
||||
{
|
||||
public:
|
||||
tree get_longjmp_caller () const;
|
||||
tree get_setjmp_caller () const;
|
||||
const exploded_edge *get_eedge () const { return m_eedge; }
|
||||
|
||||
protected:
|
||||
rewind_event (const exploded_edge *eedge,
|
||||
enum event_kind kind,
|
||||
location_t loc, tree fndecl, int depth,
|
||||
const rewind_info_t *rewind_info);
|
||||
const rewind_info_t *m_rewind_info;
|
||||
|
||||
private:
|
||||
const exploded_edge *m_eedge;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for rewinding from a longjmp to a setjmp,
|
||||
showing the longjmp (or siglongjmp). */
|
||||
|
||||
class rewind_from_longjmp_event : public rewind_event
|
||||
{
|
||||
public:
|
||||
rewind_from_longjmp_event (const exploded_edge *eedge,
|
||||
location_t loc, tree fndecl, int depth,
|
||||
const rewind_info_t *rewind_info)
|
||||
: rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc, fndecl, depth,
|
||||
rewind_info)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for rewinding from a longjmp to a setjmp,
|
||||
showing the setjmp (or sigsetjmp). */
|
||||
|
||||
class rewind_to_setjmp_event : public rewind_event
|
||||
{
|
||||
public:
|
||||
rewind_to_setjmp_event (const exploded_edge *eedge,
|
||||
location_t loc, tree fndecl, int depth,
|
||||
const rewind_info_t *rewind_info)
|
||||
: rewind_event (eedge, EK_REWIND_TO_SETJMP, loc, fndecl, depth,
|
||||
rewind_info)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
void prepare_for_emission (checker_path *path,
|
||||
pending_diagnostic *pd,
|
||||
diagnostic_event_id_t emission_id) final override;
|
||||
|
||||
private:
|
||||
diagnostic_event_id_t m_original_setjmp_event_id;
|
||||
};
|
||||
|
||||
/* Concrete subclass of checker_event for use at the end of a path:
|
||||
a repeat of the warning message at the end of the path (perhaps with
|
||||
references to pertinent events that occurred on the way), at the point
|
||||
where the problem occurs. */
|
||||
|
||||
class warning_event : public checker_event
|
||||
{
|
||||
public:
|
||||
warning_event (location_t loc, tree fndecl, int depth,
|
||||
const state_machine *sm,
|
||||
tree var, state_machine::state_t state)
|
||||
: checker_event (EK_WARNING, loc, fndecl, depth),
|
||||
m_sm (sm), m_var (var), m_state (state)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
private:
|
||||
const state_machine *m_sm;
|
||||
tree m_var;
|
||||
state_machine::state_t m_state;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_CHECKER_EVENT_H */
|
|
@ -1,4 +1,4 @@
|
|||
/* Subclasses of diagnostic_path and diagnostic_event for analyzer diagnostics.
|
||||
/* Subclass of diagnostic_path for analyzer diagnostics.
|
||||
Copyright (C) 2019-2022 Free Software Foundation, Inc.
|
||||
Contributed by David Malcolm <dmalcolm@redhat.com>.
|
||||
|
||||
|
@ -21,590 +21,10 @@ along with GCC; see the file COPYING3. If not see
|
|||
#ifndef GCC_ANALYZER_CHECKER_PATH_H
|
||||
#define GCC_ANALYZER_CHECKER_PATH_H
|
||||
|
||||
#include "tree-logical-location.h"
|
||||
#include "analyzer/checker-event.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* An enum for discriminating between the concrete subclasses of
|
||||
checker_event. */
|
||||
|
||||
enum event_kind
|
||||
{
|
||||
EK_DEBUG,
|
||||
EK_CUSTOM,
|
||||
EK_STMT,
|
||||
EK_REGION_CREATION,
|
||||
EK_FUNCTION_ENTRY,
|
||||
EK_STATE_CHANGE,
|
||||
EK_START_CFG_EDGE,
|
||||
EK_END_CFG_EDGE,
|
||||
EK_CALL_EDGE,
|
||||
EK_RETURN_EDGE,
|
||||
EK_START_CONSOLIDATED_CFG_EDGES,
|
||||
EK_END_CONSOLIDATED_CFG_EDGES,
|
||||
EK_INLINED_CALL,
|
||||
EK_SETJMP,
|
||||
EK_REWIND_FROM_LONGJMP,
|
||||
EK_REWIND_TO_SETJMP,
|
||||
EK_WARNING
|
||||
};
|
||||
|
||||
extern const char *event_kind_to_string (enum event_kind ek);
|
||||
|
||||
/* Event subclasses.
|
||||
|
||||
The class hierarchy looks like this (using indentation to show
|
||||
inheritance, and with event_kinds shown for the concrete subclasses):
|
||||
|
||||
diagnostic_event
|
||||
checker_event
|
||||
debug_event (EK_DEBUG)
|
||||
custom_event (EK_CUSTOM)
|
||||
precanned_custom_event
|
||||
statement_event (EK_STMT)
|
||||
region_creation_event (EK_REGION_CREATION)
|
||||
function_entry_event (EK_FUNCTION_ENTRY)
|
||||
state_change_event (EK_STATE_CHANGE)
|
||||
superedge_event
|
||||
cfg_edge_event
|
||||
start_cfg_edge_event (EK_START_CFG_EDGE)
|
||||
end_cfg_edge_event (EK_END_CFG_EDGE)
|
||||
call_event (EK_CALL_EDGE)
|
||||
return_edge (EK_RETURN_EDGE)
|
||||
start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES)
|
||||
end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES)
|
||||
inlined_call_event (EK_INLINED_CALL)
|
||||
setjmp_event (EK_SETJMP)
|
||||
rewind_event
|
||||
rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
|
||||
rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
|
||||
warning_event (EK_WARNING). */
|
||||
|
||||
/* Abstract subclass of diagnostic_event; the base class for use in
|
||||
checker_path (the analyzer's diagnostic_path subclass). */
|
||||
|
||||
class checker_event : public diagnostic_event
|
||||
{
|
||||
public:
|
||||
/* Implementation of diagnostic_event. */
|
||||
|
||||
location_t get_location () const final override { return m_loc; }
|
||||
tree get_fndecl () const final override { return m_effective_fndecl; }
|
||||
int get_stack_depth () const final override { return m_effective_depth; }
|
||||
const logical_location *get_logical_location () const final override
|
||||
{
|
||||
if (m_effective_fndecl)
|
||||
return &m_logical_loc;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
meaning get_meaning () const override;
|
||||
|
||||
/* Additional functionality. */
|
||||
|
||||
int get_original_stack_depth () const { return m_original_depth; }
|
||||
|
||||
virtual void prepare_for_emission (checker_path *,
|
||||
pending_diagnostic *pd,
|
||||
diagnostic_event_id_t emission_id);
|
||||
virtual bool is_call_p () const { return false; }
|
||||
virtual bool is_function_entry_p () const { return false; }
|
||||
virtual bool is_return_p () const { return false; }
|
||||
|
||||
/* For use with %@. */
|
||||
const diagnostic_event_id_t *get_id_ptr () const
|
||||
{
|
||||
return &m_emission_id;
|
||||
}
|
||||
|
||||
void dump (pretty_printer *pp) const;
|
||||
void debug () const;
|
||||
|
||||
void set_location (location_t loc) { m_loc = loc; }
|
||||
|
||||
protected:
|
||||
checker_event (enum event_kind kind,
|
||||
location_t loc, tree fndecl, int depth);
|
||||
|
||||
public:
|
||||
const enum event_kind m_kind;
|
||||
protected:
|
||||
location_t m_loc;
|
||||
tree m_original_fndecl;
|
||||
tree m_effective_fndecl;
|
||||
int m_original_depth;
|
||||
int m_effective_depth;
|
||||
pending_diagnostic *m_pending_diagnostic;
|
||||
diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
|
||||
tree_logical_location m_logical_loc;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for a purely textual event, for use in
|
||||
debugging path creation and filtering. */
|
||||
|
||||
class debug_event : public checker_event
|
||||
{
|
||||
public:
|
||||
debug_event (location_t loc, tree fndecl, int depth,
|
||||
const char *desc)
|
||||
: checker_event (EK_DEBUG, loc, fndecl, depth),
|
||||
m_desc (xstrdup (desc))
|
||||
{
|
||||
}
|
||||
~debug_event ()
|
||||
{
|
||||
free (m_desc);
|
||||
}
|
||||
|
||||
label_text get_desc (bool) const final override;
|
||||
|
||||
private:
|
||||
char *m_desc;
|
||||
};
|
||||
|
||||
/* An abstract event subclass for custom events. These are not filtered,
|
||||
as they are likely to be pertinent to the diagnostic. */
|
||||
|
||||
class custom_event : public checker_event
|
||||
{
|
||||
protected:
|
||||
custom_event (location_t loc, tree fndecl, int depth)
|
||||
: checker_event (EK_CUSTOM, loc, fndecl, depth)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/* A concrete custom_event subclass with a precanned message. */
|
||||
|
||||
class precanned_custom_event : public custom_event
|
||||
{
|
||||
public:
|
||||
precanned_custom_event (location_t loc, tree fndecl, int depth,
|
||||
const char *desc)
|
||||
: custom_event (loc, fndecl, depth),
|
||||
m_desc (xstrdup (desc))
|
||||
{
|
||||
}
|
||||
~precanned_custom_event ()
|
||||
{
|
||||
free (m_desc);
|
||||
}
|
||||
|
||||
label_text get_desc (bool) const final override;
|
||||
|
||||
private:
|
||||
char *m_desc;
|
||||
};
|
||||
|
||||
/* A concrete event subclass describing the execution of a gimple statement,
|
||||
for use at high verbosity levels when debugging paths. */
|
||||
|
||||
class statement_event : public checker_event
|
||||
{
|
||||
public:
|
||||
statement_event (const gimple *stmt, tree fndecl, int depth,
|
||||
const program_state &dst_state);
|
||||
|
||||
label_text get_desc (bool) const final override;
|
||||
|
||||
const gimple * const m_stmt;
|
||||
const program_state m_dst_state;
|
||||
};
|
||||
|
||||
/* There are too many combinations to express region creation in one message,
|
||||
so we emit multiple region_creation_event instances when each pertinent
|
||||
region is created.
|
||||
|
||||
This enum distinguishes between the different messages. */
|
||||
|
||||
enum rce_kind
|
||||
{
|
||||
/* Generate a message based on the memory space of the region
|
||||
e.g. "region created on stack here". */
|
||||
RCE_MEM_SPACE,
|
||||
|
||||
/* Generate a message based on the capacity of the region
|
||||
e.g. "capacity: 100 bytes". */
|
||||
RCE_CAPACITY,
|
||||
|
||||
/* Generate a debug message. */
|
||||
RCE_DEBUG
|
||||
};
|
||||
|
||||
/* A concrete event subclass describing the creation of a region that
|
||||
is significant for a diagnostic. */
|
||||
|
||||
class region_creation_event : public checker_event
|
||||
{
|
||||
public:
|
||||
region_creation_event (const region *reg,
|
||||
tree capacity,
|
||||
enum rce_kind kind,
|
||||
location_t loc, tree fndecl, int depth);
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
private:
|
||||
const region *m_reg;
|
||||
tree m_capacity;
|
||||
enum rce_kind m_rce_kind;
|
||||
};
|
||||
|
||||
/* An event subclass describing the entry to a function. */
|
||||
|
||||
class function_entry_event : public checker_event
|
||||
{
|
||||
public:
|
||||
function_entry_event (location_t loc, tree fndecl, int depth)
|
||||
: checker_event (EK_FUNCTION_ENTRY, loc, fndecl, depth)
|
||||
{
|
||||
}
|
||||
|
||||
function_entry_event (const program_point &dst_point);
|
||||
|
||||
label_text get_desc (bool can_colorize) const override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
bool is_function_entry_p () const final override { return true; }
|
||||
};
|
||||
|
||||
/* Subclass of checker_event describing a state change. */
|
||||
|
||||
class state_change_event : public checker_event
|
||||
{
|
||||
public:
|
||||
state_change_event (const supernode *node, const gimple *stmt,
|
||||
int stack_depth,
|
||||
const state_machine &sm,
|
||||
const svalue *sval,
|
||||
state_machine::state_t from,
|
||||
state_machine::state_t to,
|
||||
const svalue *origin,
|
||||
const program_state &dst_state);
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
function *get_dest_function () const
|
||||
{
|
||||
return m_dst_state.get_current_function ();
|
||||
}
|
||||
|
||||
const supernode *m_node;
|
||||
const gimple *m_stmt;
|
||||
const state_machine &m_sm;
|
||||
const svalue *m_sval;
|
||||
state_machine::state_t m_from;
|
||||
state_machine::state_t m_to;
|
||||
const svalue *m_origin;
|
||||
program_state m_dst_state;
|
||||
};
|
||||
|
||||
/* Subclass of checker_event; parent class for subclasses that relate to
|
||||
a superedge. */
|
||||
|
||||
class superedge_event : public checker_event
|
||||
{
|
||||
public:
|
||||
/* Mark this edge event as being either an interprocedural call or
|
||||
return in which VAR is in STATE, and that this is critical to the
|
||||
diagnostic (so that get_desc can attempt to get a better description
|
||||
from any pending_diagnostic). */
|
||||
void record_critical_state (tree var, state_machine::state_t state)
|
||||
{
|
||||
m_var = var;
|
||||
m_critical_state = state;
|
||||
}
|
||||
|
||||
const callgraph_superedge& get_callgraph_superedge () const;
|
||||
|
||||
bool should_filter_p (int verbosity) const;
|
||||
|
||||
protected:
|
||||
superedge_event (enum event_kind kind, const exploded_edge &eedge,
|
||||
location_t loc, tree fndecl, int depth);
|
||||
|
||||
public:
|
||||
const exploded_edge &m_eedge;
|
||||
const superedge *m_sedge;
|
||||
tree m_var;
|
||||
state_machine::state_t m_critical_state;
|
||||
};
|
||||
|
||||
/* An abstract event subclass for when a CFG edge is followed; it has two
|
||||
subclasses, representing the start of the edge and the end of the
|
||||
edge, which come in pairs. */
|
||||
|
||||
class cfg_edge_event : public superedge_event
|
||||
{
|
||||
public:
|
||||
meaning get_meaning () const override;
|
||||
|
||||
const cfg_superedge& get_cfg_superedge () const;
|
||||
|
||||
protected:
|
||||
cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
|
||||
location_t loc, tree fndecl, int depth);
|
||||
};
|
||||
|
||||
/* A concrete event subclass for the start of a CFG edge
|
||||
e.g. "following 'false' branch...'. */
|
||||
|
||||
class start_cfg_edge_event : public cfg_edge_event
|
||||
{
|
||||
public:
|
||||
start_cfg_edge_event (const exploded_edge &eedge,
|
||||
location_t loc, tree fndecl, int depth)
|
||||
: cfg_edge_event (EK_START_CFG_EDGE, eedge, loc, fndecl, depth)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
private:
|
||||
label_text maybe_describe_condition (bool can_colorize) const;
|
||||
|
||||
static label_text maybe_describe_condition (bool can_colorize,
|
||||
tree lhs,
|
||||
enum tree_code op,
|
||||
tree rhs);
|
||||
static bool should_print_expr_p (tree);
|
||||
};
|
||||
|
||||
/* A concrete event subclass for the end of a CFG edge
|
||||
e.g. "...to here'. */
|
||||
|
||||
class end_cfg_edge_event : public cfg_edge_event
|
||||
{
|
||||
public:
|
||||
end_cfg_edge_event (const exploded_edge &eedge,
|
||||
location_t loc, tree fndecl, int depth)
|
||||
: cfg_edge_event (EK_END_CFG_EDGE, eedge, loc, fndecl, depth)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool /*can_colorize*/) const final override
|
||||
{
|
||||
return label_text::borrow ("...to here");
|
||||
}
|
||||
};
|
||||
|
||||
/* A concrete event subclass for an interprocedural call. */
|
||||
|
||||
class call_event : public superedge_event
|
||||
{
|
||||
public:
|
||||
call_event (const exploded_edge &eedge,
|
||||
location_t loc, tree fndecl, int depth);
|
||||
|
||||
label_text get_desc (bool can_colorize) const override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
bool is_call_p () const final override;
|
||||
|
||||
protected:
|
||||
tree get_caller_fndecl () const;
|
||||
tree get_callee_fndecl () const;
|
||||
|
||||
const supernode *m_src_snode;
|
||||
const supernode *m_dest_snode;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for an interprocedural return. */
|
||||
|
||||
class return_event : public superedge_event
|
||||
{
|
||||
public:
|
||||
return_event (const exploded_edge &eedge,
|
||||
location_t loc, tree fndecl, int depth);
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
bool is_return_p () const final override;
|
||||
|
||||
const supernode *m_src_snode;
|
||||
const supernode *m_dest_snode;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for the start of a consolidated run of CFG
|
||||
edges all either TRUE or FALSE e.g. "following 'false' branch...'. */
|
||||
|
||||
class start_consolidated_cfg_edges_event : public checker_event
|
||||
{
|
||||
public:
|
||||
start_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth,
|
||||
bool edge_sense)
|
||||
: checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth),
|
||||
m_edge_sense (edge_sense)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
private:
|
||||
bool m_edge_sense;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for the end of a consolidated run of
|
||||
CFG edges e.g. "...to here'. */
|
||||
|
||||
class end_consolidated_cfg_edges_event : public checker_event
|
||||
{
|
||||
public:
|
||||
end_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth)
|
||||
: checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool /*can_colorize*/) const final override
|
||||
{
|
||||
return label_text::borrow ("...to here");
|
||||
}
|
||||
};
|
||||
|
||||
/* A concrete event subclass for describing an inlined call event
|
||||
e.g. "inlined call to 'callee' from 'caller'". */
|
||||
|
||||
class inlined_call_event : public checker_event
|
||||
{
|
||||
public:
|
||||
inlined_call_event (location_t loc,
|
||||
tree apparent_callee_fndecl,
|
||||
tree apparent_caller_fndecl,
|
||||
int actual_depth,
|
||||
int stack_depth_adjustment)
|
||||
: checker_event (EK_INLINED_CALL, loc,
|
||||
apparent_caller_fndecl,
|
||||
actual_depth + stack_depth_adjustment),
|
||||
m_apparent_callee_fndecl (apparent_callee_fndecl),
|
||||
m_apparent_caller_fndecl (apparent_caller_fndecl)
|
||||
{
|
||||
gcc_assert (LOCATION_BLOCK (loc) == NULL);
|
||||
}
|
||||
|
||||
label_text get_desc (bool /*can_colorize*/) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
private:
|
||||
tree m_apparent_callee_fndecl;
|
||||
tree m_apparent_caller_fndecl;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for a setjmp or sigsetjmp call. */
|
||||
|
||||
class setjmp_event : public checker_event
|
||||
{
|
||||
public:
|
||||
setjmp_event (location_t loc, const exploded_node *enode,
|
||||
tree fndecl, int depth, const gcall *setjmp_call)
|
||||
: checker_event (EK_SETJMP, loc, fndecl, depth),
|
||||
m_enode (enode), m_setjmp_call (setjmp_call)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
void prepare_for_emission (checker_path *path,
|
||||
pending_diagnostic *pd,
|
||||
diagnostic_event_id_t emission_id) final override;
|
||||
|
||||
private:
|
||||
const exploded_node *m_enode;
|
||||
const gcall *m_setjmp_call;
|
||||
};
|
||||
|
||||
/* An abstract event subclass for rewinding from a longjmp to a setjmp
|
||||
(or siglongjmp to sigsetjmp).
|
||||
|
||||
Base class for two from/to subclasses, showing the two halves of the
|
||||
rewind. */
|
||||
|
||||
class rewind_event : public checker_event
|
||||
{
|
||||
public:
|
||||
tree get_longjmp_caller () const;
|
||||
tree get_setjmp_caller () const;
|
||||
const exploded_edge *get_eedge () const { return m_eedge; }
|
||||
|
||||
protected:
|
||||
rewind_event (const exploded_edge *eedge,
|
||||
enum event_kind kind,
|
||||
location_t loc, tree fndecl, int depth,
|
||||
const rewind_info_t *rewind_info);
|
||||
const rewind_info_t *m_rewind_info;
|
||||
|
||||
private:
|
||||
const exploded_edge *m_eedge;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for rewinding from a longjmp to a setjmp,
|
||||
showing the longjmp (or siglongjmp). */
|
||||
|
||||
class rewind_from_longjmp_event : public rewind_event
|
||||
{
|
||||
public:
|
||||
rewind_from_longjmp_event (const exploded_edge *eedge,
|
||||
location_t loc, tree fndecl, int depth,
|
||||
const rewind_info_t *rewind_info)
|
||||
: rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc, fndecl, depth,
|
||||
rewind_info)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for rewinding from a longjmp to a setjmp,
|
||||
showing the setjmp (or sigsetjmp). */
|
||||
|
||||
class rewind_to_setjmp_event : public rewind_event
|
||||
{
|
||||
public:
|
||||
rewind_to_setjmp_event (const exploded_edge *eedge,
|
||||
location_t loc, tree fndecl, int depth,
|
||||
const rewind_info_t *rewind_info)
|
||||
: rewind_event (eedge, EK_REWIND_TO_SETJMP, loc, fndecl, depth,
|
||||
rewind_info)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
void prepare_for_emission (checker_path *path,
|
||||
pending_diagnostic *pd,
|
||||
diagnostic_event_id_t emission_id) final override;
|
||||
|
||||
private:
|
||||
diagnostic_event_id_t m_original_setjmp_event_id;
|
||||
};
|
||||
|
||||
/* Concrete subclass of checker_event for use at the end of a path:
|
||||
a repeat of the warning message at the end of the path (perhaps with
|
||||
references to pertinent events that occurred on the way), at the point
|
||||
where the problem occurs. */
|
||||
|
||||
class warning_event : public checker_event
|
||||
{
|
||||
public:
|
||||
warning_event (location_t loc, tree fndecl, int depth,
|
||||
const state_machine *sm,
|
||||
tree var, state_machine::state_t state)
|
||||
: checker_event (EK_WARNING, loc, fndecl, depth),
|
||||
m_sm (sm), m_var (var), m_state (state)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
private:
|
||||
const state_machine *m_sm;
|
||||
tree m_var;
|
||||
state_machine::state_t m_state;
|
||||
};
|
||||
|
||||
/* Subclass of diagnostic_path for analyzer diagnostics. */
|
||||
|
||||
class checker_path : public diagnostic_path
|
||||
|
|
Loading…
Add table
Reference in a new issue