return "EK_CUSTOM";
case EK_STMT:
return "EK_STMT";
+ case EK_REGION_CREATION:
+ return "EK_REGION_CREATION";
case EK_FUNCTION_ENTRY:
return "EK_FUNCTION_ENTRY";
case EK_STATE_CHANGE:
return label_text::take (xstrdup (pp_formatted_text (&pp)));
}
+/* class region_creation_event : public checker_event. */
+
+region_creation_event::region_creation_event (const region *reg,
+ location_t loc,
+ tree fndecl,
+ int depth)
+: checker_event (EK_REGION_CREATION, loc, fndecl, depth),
+ m_reg (reg)
+{
+}
+
+/* Implementation of diagnostic_event::get_desc vfunc for
+ region_creation_event. */
+
+label_text
+region_creation_event::get_desc (bool) const
+{
+ switch (m_reg->get_memory_space ())
+ {
+ default:
+ return label_text::borrow ("region created here");
+ case MEMSPACE_STACK:
+ return label_text::borrow ("region created on stack here");
+ case MEMSPACE_HEAP:
+ return label_text::borrow ("region created on heap here");
+ }
+}
+
/* class function_entry_event : public checker_event. */
/* Implementation of diagnostic_event::get_desc vfunc for
}
}
+/* Add region_creation_event instance to this path for REG,
+ describing whether REG is on the stack or heap. */
+
+void
+checker_path::add_region_creation_event (const region *reg,
+ location_t loc,
+ tree fndecl, int depth)
+{
+ add_event (new region_creation_event (reg, loc, fndecl, depth));
+}
+
/* Add a warning_event to the end of this path. */
void
EK_DEBUG,
EK_CUSTOM,
EK_STMT,
+ EK_REGION_CREATION,
EK_FUNCTION_ENTRY,
EK_STATE_CHANGE,
EK_START_CFG_EDGE,
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
const program_state m_dst_state;
};
+/* A concrete event subclass describing the creation of a region that
+ is significant for a diagnostic e.g. "region created on stack here". */
+
+class region_creation_event : public checker_event
+{
+public:
+ region_creation_event (const region *reg,
+ location_t loc, tree fndecl, int depth);
+
+ label_text get_desc (bool) const FINAL OVERRIDE;
+
+private:
+ const region *m_reg;
+};
+
/* An event subclass describing the entry to a function. */
class function_entry_event : public checker_event
m_events[idx] = new_event;
}
+ void add_region_creation_event (const region *reg,
+ location_t loc,
+ tree fndecl, int depth);
+
void add_final_event (const state_machine *sm,
const exploded_node *enode, const gimple *stmt,
tree var, state_machine::state_t state);
trailing eedge stashed, add any events for it. This is for use
in handling longjmp, to show where a longjmp is rewinding to. */
if (sd.m_trailing_eedge)
- add_events_for_eedge (pb, *sd.m_trailing_eedge, &emission_path);
+ add_events_for_eedge (pb, *sd.m_trailing_eedge, &emission_path, NULL);
emission_path.prepare_for_emission (sd.m_d);
checker_path *emission_path) const
{
LOG_SCOPE (get_logger ());
+
+ interesting_t interest;
+ pb.get_pending_diagnostic ()->mark_interesting_stuff (&interest);
for (unsigned i = 0; i < epath.m_edges.length (); i++)
{
const exploded_edge *eedge = epath.m_edges[i];
- add_events_for_eedge (pb, *eedge, emission_path);
+ add_events_for_eedge (pb, *eedge, emission_path, &interest);
}
}
void
diagnostic_manager::add_events_for_eedge (const path_builder &pb,
const exploded_edge &eedge,
- checker_path *emission_path) const
+ checker_path *emission_path,
+ interesting_t *interest) const
{
const exploded_node *src_node = eedge.m_src;
const program_point &src_point = src_node->get_point ();
+ const int src_stack_depth = src_point.get_stack_depth ();
const exploded_node *dst_node = eedge.m_dest;
const program_point &dst_point = dst_node->get_point ();
const int dst_stack_depth = dst_point.get_stack_depth ();
(dst_point.get_supernode ()->get_start_location (),
dst_point.get_fndecl (),
dst_stack_depth));
+ /* Create region_creation_events for on-stack regions within
+ this frame. */
+ if (interest)
+ {
+ unsigned i;
+ const region *reg;
+ FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg)
+ if (const frame_region *frame = reg->maybe_get_frame_region ())
+ if (frame->get_fndecl () == dst_point.get_fndecl ())
+ {
+ const region *base_reg = reg->get_base_region ();
+ if (tree decl = base_reg->maybe_get_decl ())
+ if (DECL_P (decl)
+ && DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION)
+ {
+ emission_path->add_region_creation_event
+ (reg,
+ DECL_SOURCE_LOCATION (decl),
+ dst_point.get_fndecl (),
+ dst_stack_depth);
+ }
+ }
+ }
}
break;
case PK_BEFORE_STMT:
== dst_node->m_succs[0]->m_dest->get_point ())))
break;
}
+
+ /* Look for changes in dynamic extents, which will identify
+ the creation of heap-based regions and alloca regions. */
+ if (interest)
+ {
+ const region_model *src_model = src_state.m_region_model;
+ const region_model *dst_model = dst_state.m_region_model;
+ if (src_model->get_dynamic_extents ()
+ != dst_model->get_dynamic_extents ())
+ {
+ unsigned i;
+ const region *reg;
+ FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg)
+ {
+ const region *base_reg = reg->get_base_region ();
+ const svalue *old_extents
+ = src_model->get_dynamic_extents (base_reg);
+ const svalue *new_extents
+ = dst_model->get_dynamic_extents (base_reg);
+ if (old_extents == NULL && new_extents != NULL)
+ switch (base_reg->get_kind ())
+ {
+ default:
+ break;
+ case RK_HEAP_ALLOCATED:
+ case RK_ALLOCA:
+ emission_path->add_region_creation_event
+ (reg,
+ src_point.get_location (),
+ src_point.get_fndecl (),
+ src_stack_depth);
+ break;
+ }
+ }
+ }
+ }
}
}
break;
}
break;
+ case EK_REGION_CREATION:
+ /* Don't filter these. */
+ break;
+
case EK_FUNCTION_ENTRY:
if (m_verbosity < 1)
{
void add_events_for_eedge (const path_builder &pb,
const exploded_edge &eedge,
- checker_path *emission_path) const;
+ checker_path *emission_path,
+ interesting_t *interest) const;
bool significant_edge_p (const path_builder &pb,
const exploded_edge &eedge) const;
#include "diagnostic-event-id.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
+#include "selftest.h"
+#include "tristate.h"
+#include "analyzer/call-string.h"
+#include "analyzer/program-point.h"
+#include "analyzer/store.h"
+#include "analyzer/region-model.h"
#if ENABLE_ANALYZER
namespace ana {
+/* struct interesting_t. */
+
+/* Mark the creation of REG as being interesting. */
+
+void
+interesting_t::add_region_creation (const region *reg)
+{
+ gcc_assert (reg);
+ m_region_creation.safe_push (reg);
+}
+
+void
+interesting_t::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+ pp_string (pp, "{ region creation: [");
+ unsigned i;
+ const region *reg;
+ FOR_EACH_VEC_ELT (m_region_creation, i, reg)
+ {
+ if (i > 0)
+ pp_string (pp, ", ");
+ reg->dump_to_pp (pp, simple);
+ }
+ pp_string (pp, "]}");
+}
+
/* Generate a label_text by printing FMT.
Use a clone of the global_dc for formatting callbacks.
namespace ana {
+/* A bundle of information about things that are of interest to a
+ pending_diagnostic.
+
+ For now, merely the set of regions that are pertinent to the
+ diagnostic, so that we can notify the user about when they
+ were created. */
+
+struct interesting_t
+{
+ void add_region_creation (const region *reg);
+
+ void dump_to_pp (pretty_printer *pp, bool simple) const;
+
+ auto_vec<const region *> m_region_creation;
+};
+
/* Various bundles of information used for generating more precise
messages for events within a diagnostic_path, for passing to the
various "describe_*" vfuncs of pending_diagnostic. See those
{
return false;
}
+
+ /* Vfunc for registering additional information of interest to this
+ diagnostic. */
+
+ virtual void mark_interesting_stuff (interesting_t *)
+ {
+ /* Default no-op implementation. */
+ }
};
/* A template to make it easier to make subclasses of pending_diagnostic.
: public pending_diagnostic_subclass<poisoned_value_diagnostic>
{
public:
- poisoned_value_diagnostic (tree expr, enum poison_kind pkind)
- : m_expr (expr), m_pkind (pkind)
+ poisoned_value_diagnostic (tree expr, enum poison_kind pkind,
+ const region *src_region)
+ : m_expr (expr), m_pkind (pkind),
+ m_src_region (src_region)
{}
const char *get_kind () const FINAL OVERRIDE { return "poisoned_value_diagnostic"; }
bool operator== (const poisoned_value_diagnostic &other) const
{
- return m_expr == other.m_expr;
+ return (m_expr == other.m_expr
+ && m_pkind == other.m_pkind
+ && m_src_region == other.m_src_region);
}
bool emit (rich_location *rich_loc) FINAL OVERRIDE
}
}
+ void mark_interesting_stuff (interesting_t *interest) FINAL OVERRIDE
+ {
+ if (m_src_region)
+ interest->add_region_creation (m_src_region);
+ }
+
private:
tree m_expr;
enum poison_kind m_pkind;
+ const region *m_src_region;
};
/* A subclass of pending_diagnostic for complaining about shifts
fixup_tree_for_diagnostic. */
tree diag_arg = fixup_tree_for_diagnostic (expr);
enum poison_kind pkind = poisoned_sval->get_poison_kind ();
- if (ctxt->warn (new poisoned_value_diagnostic (diag_arg, pkind)))
+ const region *src_region = NULL;
+ if (pkind == POISON_KIND_UNINIT)
+ src_region = get_region_for_poisoned_expr (expr);
+ if (ctxt->warn (new poisoned_value_diagnostic (diag_arg, pkind,
+ src_region)))
{
/* We only want to report use of a poisoned value at the first
place it gets used; return an unknown value to avoid generating
return sval;
}
+/* Attempt to get a region for describing EXPR, the source of region of
+ a poisoned_svalue for use in a poisoned_value_diagnostic.
+ Return NULL if there is no good region to use. */
+
+const region *
+region_model::get_region_for_poisoned_expr (tree expr) const
+{
+ if (TREE_CODE (expr) == SSA_NAME)
+ {
+ tree decl = SSA_NAME_VAR (expr);
+ if (decl && DECL_P (decl))
+ expr = decl;
+ else
+ return NULL;
+ }
+ return get_lvalue (expr, NULL);
+}
+
/* Update this model for the ASSIGN stmt, using CTXT to report any
diagnostics. */
const poisoned_svalue *poisoned_sval
= as_a <const poisoned_svalue *> (ptr_sval);
enum poison_kind pkind = poisoned_sval->get_poison_kind ();
- ctxt->warn (new poisoned_value_diagnostic (ptr, pkind));
+ ctxt->warn (new poisoned_value_diagnostic (ptr, pkind, NULL));
}
}
}
const svalue *check_for_poison (const svalue *sval,
tree expr,
region_model_context *ctxt) const;
+ const region * get_region_for_poisoned_expr (tree expr) const;
void check_dynamic_size_for_taint (enum memory_space mem_space,
const svalue *size_in_bytes,
/* Accessors. */
const frame_region *get_calling_frame () const { return m_calling_frame; }
function *get_function () const { return m_fun; }
+ tree get_fndecl () const { return get_function ()->decl; }
int get_index () const { return m_index; }
int get_stack_depth () const { return m_index + 1; }
/* Use of uninit value. */
int test_12a (void)
{
- int i;
+ int i; /* { dg-message "region created on stack here" } */
return i; /* { dg-warning "use of uninitialized value 'i'" } */
}
int test_12c (void)
{
- int i;
+ int i; /* { dg-message "region created on stack here" } */
int j;
j = i; /* { dg-warning "use of uninitialized value 'i'" } */
void test_19 (void)
{
- int i, j;
+ int i, j; /* { dg-message "region created on stack here" } */
/* Compare two uninitialized locals. */
__analyzer_eval (i == j); /* { dg-warning "UNKNOWN" "unknown " } */
/* { dg-warning "use of uninitialized value 'i'" "uninit i" { target *-*-* } .-1 } */
void test_29b (void)
{
- struct coord p[11];
+ struct coord p[11]; /* { dg-message "region created on stack here" } */
struct coord *q;
p[0].x = 100024;
int test_37 (void)
{
- int *ptr;
+ int *ptr; /* { dg-message "region created on stack here" } */
return *ptr; /* { dg-warning "use of uninitialized value 'ptr'" } */
}
void test_37a (int i)
{
- int *ptr;
+ int *ptr; /* { dg-message "region created on stack here" } */
*ptr = i; /* { dg-warning "use of uninitialized value 'ptr'" } */
}
void test_16 (void)
{
- void *p, *q;
+ void *p, *q; /* { dg-message "region created on stack here" } */
p = malloc (1024);
if (!p)
int *
test_40 (int i)
{
- int *p = (int*)malloc(sizeof(int*));
+ int *p = (int*)malloc(sizeof(int*)); /* { dg-message "region created on heap here" } */
i = *p; /* { dg-warning "dereference of possibly-NULL 'p' \\\[CWE-690\\\]" "possibly-null" } */
/* { dg-warning "use of uninitialized value '\\*p'" "uninit" { target *-*-*} .-1 } */
return p;
/* [...snip...] */
- struct aac_srb_reply reply;
+ struct aac_srb_reply reply; /* { dg-message "region created on stack here" } */
reply.status = ST_OK;
k2 (void)
{
char *setfiles[1];
- int i;
+ int i; /* { dg-message "region created on stack here" } */
setfiles[i] = fopen ("", ""); /* { dg-warning "use of uninitialized value 'i'" } */
} /* { dg-warning "leak of FILE" } */
k2 (void)
{
char *setfiles[1];
- int i;
+ int i; /* { dg-message "region created on stack here" } */
setfiles[i] = fopen("", ""); /* { dg-warning "use of uninitialized value 'i'" } */
if (!setfiles[i]) /* { dg-warning "use of uninitialized value 'i'" } */
int
test_1 (void)
{
- int stack;
+ int stack; /* { dg-message "region created on stack here" } */
int *a = &stack;
a = maybe_inc_int_ptr (a);
a = maybe_inc_int_ptr (a);
int main(void)
{
- struct test t;
- int num;
+ struct test t; /* { dg-message "region created on stack here" } */
+ int num; /* { dg-message "region created on stack here" } */
int arry[10];
- int arry_2[10];
- int go;
+ int arry_2[10]; /* { dg-message "region created on stack here" } */
+ int go; /* { dg-message "region created on stack here" } */
int color = BLACK;
func1(&t);
void
foo (void)
{
- struct list l;
+ struct list l; /* { dg-message "region created on stack here" } */
tlist t = l; /* { dg-warning "use of uninitialized value 'l'" } */
for (;;)
bar (&t);
void test_1 (char a, char b, char c, char d, char e, char f,
int i, int j)
{
- char arr[1024];
+ char arr[1024]; /* { dg-message "region created on stack here" } */
arr[2] = a; /* (1) */
arr[3] = b; /* (2) */
int test_1 (void)
{
- int i;
+ int i; /* { dg-message "region created on stack here" } */
return i; /* { dg-warning "use of uninitialized value 'i'" } */
}
int test_2 (void)
{
- int i;
+ int i; /* { dg-message "region created on stack here" } */
return i * 2; /* { dg-warning "use of uninitialized value 'i'" } */
}
int test_4 (void)
{
- int *p;
+ int *p; /* { dg-message "region created on stack here" } */
return *p; /* { dg-warning "use of uninitialized value 'p'" } */
}
int test_5 (int flag, int *q)
{
- int *p;
+ int *p; /* { dg-message "region created on stack here" } */
if (flag) /* { dg-message "following 'false' branch" } */
p = q;
int test_6 (int i)
{
- int arr[10];
+ int arr[10]; /* { dg-message "region created on stack here" } */
return arr[i]; /* { dg-warning "use of uninitialized value 'arr\\\[i\\\]'" } */
}
struct foo *__attribute__((noinline))
alloc_foo (int a, int b)
{
- struct foo *p = malloc (sizeof (struct foo));
+ struct foo *p = malloc (sizeof (struct foo)); /* { dg-message "region created on heap here" } */
if (!p)
return NULL;
p->i = a;
--- /dev/null
+/* { dg-require-effective-target alloca } */
+
+int test_1 (void)
+{
+ int *p = __builtin_alloca (sizeof (int)); /* { dg-message "region created on stack here" } */
+ return *p; /* { dg-warning "use of uninitialized value '\\*p'" } */
+}
int foo (void)
{
- int *p;
+ int *p; /* { dg-message "region created on stack here" } */
f1 (p); /* { dg-warning "use of uninitialized value 'p'" } */
f2 (p[0]); /* { dg-warning "use of uninitialized value 'p'" } */
int main (void)
{
int *p;
- int i;
+ int i; /* { dg-message "region created on stack here" } */
p = &i; /* { dg-bogus "uninitialized" } */
printf ("%d\n", p[0]); /* { dg-warning "use of uninitialized value '\\*p'" } */
uInt mask;
register uInt *p;
inflate_huft *q;
- struct inflate_huft_s r;
+ struct inflate_huft_s r; /* { dg-message "region created on stack here" } */
inflate_huft *u[15];
register int w;
uInt x[15 + 1];