mirror of
https://gcc.gnu.org/git/gcc.git
synced 2026-02-22 12:00:03 -05:00
Compare commits
3 Commits
devel/fort
...
devel/anal
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24918a9b20 | ||
|
|
d666ae9862 | ||
|
|
71dcf0c4aa |
@@ -94,6 +94,10 @@ Wanalyzer-use-after-free
|
||||
Common Var(warn_analyzer_use_after_free) Init(1) Warning
|
||||
Warn about code paths in which a freed value is used.
|
||||
|
||||
Wanalyzer-use-of-closed-file
|
||||
Common Var(warn_analyzer_use_of_closed_file) Init(1) Warning
|
||||
Warn about code paths in which a FILE * is used after being closed.
|
||||
|
||||
Wanalyzer-use-of-pointer-in-stale-stack-frame
|
||||
Common Var(warn_analyzer_use_of_pointer_in_stale_stack_frame) Init(1) Warning
|
||||
Warn about code paths in which a pointer to a stale stack frame is used.
|
||||
|
||||
@@ -161,6 +161,46 @@ private:
|
||||
diagnostic_event_id_t m_first_fclose_event;
|
||||
};
|
||||
|
||||
class use_of_closed_file : public file_diagnostic
|
||||
{
|
||||
public:
|
||||
use_of_closed_file (const fileptr_state_machine &sm, tree arg)
|
||||
: file_diagnostic (sm, arg)
|
||||
{}
|
||||
|
||||
const char *get_kind () const FINAL OVERRIDE { return "use_of_closed_file"; }
|
||||
|
||||
bool emit (rich_location *rich_loc) FINAL OVERRIDE
|
||||
{
|
||||
// FIXME: CWE?
|
||||
return warning_at (rich_loc, OPT_Wanalyzer_use_of_closed_file,
|
||||
"use of closed FILE %qE",
|
||||
m_arg);
|
||||
}
|
||||
|
||||
label_text describe_state_change (const evdesc::state_change &change)
|
||||
OVERRIDE
|
||||
{
|
||||
if (change.m_new_state == m_sm.m_closed)
|
||||
{
|
||||
m_fclose_event = change.m_event_id;
|
||||
return change.formatted_print ("file closed here");
|
||||
}
|
||||
return file_diagnostic::describe_state_change (change);
|
||||
}
|
||||
|
||||
label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
|
||||
{
|
||||
if (m_fclose_event.known_p ())
|
||||
return ev.formatted_print ("use of closed FILE %qE; closed at %@",
|
||||
ev.m_expr, &m_fclose_event);
|
||||
return ev.formatted_print ("use of closed FILE %qE", ev.m_expr);
|
||||
}
|
||||
|
||||
private:
|
||||
diagnostic_event_id_t m_fclose_event;
|
||||
};
|
||||
|
||||
class file_leak : public file_diagnostic
|
||||
{
|
||||
public:
|
||||
@@ -294,6 +334,41 @@ is_file_using_fn_p (tree fndecl)
|
||||
return fs.contains_decl_p (fndecl);
|
||||
}
|
||||
|
||||
/* If FNDECL takes a FILE * param, write the 0-based index of the first
|
||||
such param to *OUT_IDX and return true. */
|
||||
|
||||
static bool
|
||||
find_file_param (tree fndecl, int *out_idx)
|
||||
{
|
||||
int idx = 0;
|
||||
for (tree iter_param_types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
|
||||
iter_param_types;
|
||||
iter_param_types = TREE_CHAIN (iter_param_types), idx++)
|
||||
{
|
||||
tree param_type = TREE_VALUE (iter_param_types);
|
||||
|
||||
/* Looks like we can't rely on fileptr_type_node being set up;
|
||||
instead, look for a ptr to record called "FILE". */
|
||||
|
||||
if (!POINTER_TYPE_P (param_type))
|
||||
continue;
|
||||
tree type = TREE_TYPE (param_type);
|
||||
if (TREE_CODE (type) == RECORD_TYPE
|
||||
&& TYPE_NAME (type)
|
||||
&& TREE_CODE (TYPE_NAME (type)) == TYPE_DECL)
|
||||
{
|
||||
tree tdecl = TYPE_NAME (type);
|
||||
if (DECL_NAME (tdecl)
|
||||
&& strcmp (IDENTIFIER_POINTER (DECL_NAME (tdecl)), "FILE") == 0)
|
||||
{
|
||||
*out_idx = idx;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Implementation of state_machine::on_stmt vfunc for fileptr_state_machine. */
|
||||
|
||||
bool
|
||||
@@ -340,12 +415,27 @@ fileptr_state_machine::on_stmt (sm_context *sm_ctxt,
|
||||
|
||||
if (is_file_using_fn_p (callee_fndecl))
|
||||
{
|
||||
// TODO: operations on unchecked file
|
||||
int param_idx;
|
||||
if (find_file_param (callee_fndecl, ¶m_idx))
|
||||
{
|
||||
/* Look up FILE * param. */
|
||||
tree arg = gimple_call_arg (call, param_idx);
|
||||
arg = sm_ctxt->get_readable_tree (arg);
|
||||
|
||||
// TODO: operations on unchecked file
|
||||
|
||||
/* Complain about operations on closed files. */
|
||||
sm_ctxt->warn_for_state (node, stmt, arg, m_closed,
|
||||
new use_of_closed_file (*this, arg));
|
||||
sm_ctxt->on_transition (node, stmt, arg, m_closed, m_stop);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// etc
|
||||
}
|
||||
|
||||
// TODO: fcloseall() (a GNU extension)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -295,7 +295,9 @@ diagnostic_output_format_init (diagnostic_context *context,
|
||||
context->begin_group_cb = json_begin_group;
|
||||
context->end_group_cb = json_end_group;
|
||||
context->final_cb = json_final_cb;
|
||||
context->print_path = NULL; /* handled in json_end_diagnostic. */
|
||||
/* Handled in json_end_diagnostic: */
|
||||
delete context->m_path_printer;
|
||||
context->m_path_printer = NULL;
|
||||
|
||||
/* The metadata is handled in JSON format, rather than as text. */
|
||||
context->show_cwe = false;
|
||||
|
||||
@@ -2565,6 +2565,13 @@ diagnostic_show_locus (diagnostic_context * context,
|
||||
|
||||
context->last_location = loc;
|
||||
|
||||
/* If we have a path that which when printed would make printing
|
||||
RICHLOC redundant, then print that now instead. */
|
||||
if (context->m_path_printer)
|
||||
if (context->m_path_printer->maybe_print_path_rather_than_richloc
|
||||
(context, *richloc))
|
||||
return;
|
||||
|
||||
layout layout (context, richloc, diagnostic_kind);
|
||||
for (int line_span_idx = 0; line_span_idx < layout.get_num_line_spans ();
|
||||
line_span_idx++)
|
||||
|
||||
@@ -210,6 +210,8 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
|
||||
context->get_option_url = NULL;
|
||||
context->last_location = UNKNOWN_LOCATION;
|
||||
context->last_module = 0;
|
||||
context->m_path_printer = NULL;
|
||||
context->make_json_for_path = NULL;
|
||||
context->x_data = NULL;
|
||||
context->lock = 0;
|
||||
context->inhibit_notes_p = false;
|
||||
@@ -286,6 +288,9 @@ diagnostic_finish (diagnostic_context *context)
|
||||
XDELETE (context->printer);
|
||||
context->printer = NULL;
|
||||
|
||||
delete context->m_path_printer;
|
||||
context->m_path_printer = NULL;
|
||||
|
||||
if (context->edit_context_ptr)
|
||||
{
|
||||
delete context->edit_context_ptr;
|
||||
@@ -672,8 +677,8 @@ diagnostic_show_any_path (diagnostic_context *context,
|
||||
if (!path)
|
||||
return;
|
||||
|
||||
if (context->print_path)
|
||||
context->print_path (context, path);
|
||||
if (context->m_path_printer)
|
||||
context->m_path_printer->print_path (context, *diagnostic->richloc);
|
||||
}
|
||||
|
||||
/* Return true if the events in this path involve more than one
|
||||
@@ -693,6 +698,40 @@ diagnostic_path::interprocedural_p () const
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if it would be redundant to print this rich_location with
|
||||
diagnostic_show_locus if we were to also then print the path of this
|
||||
rich_location.
|
||||
|
||||
Specifically return true if this rich_location has a single location,
|
||||
and a path, no fix-it hints or labels, and the single location is
|
||||
within the path.
|
||||
|
||||
Implemented here as libcpp has only a forward decl of diagnostic_path. */
|
||||
|
||||
bool
|
||||
rich_location::path_makes_location_redundant_p () const
|
||||
{
|
||||
if (m_path == NULL)
|
||||
return false;
|
||||
if (get_num_locations () != 1)
|
||||
return false;
|
||||
|
||||
/* Must be no fix-it hints or labels. */
|
||||
if (get_num_fixit_hints () > 0)
|
||||
return false;
|
||||
const location_range *lr = get_range (0);
|
||||
if (lr->m_label)
|
||||
return false;
|
||||
|
||||
/* Check if primary location is within path. */
|
||||
location_t loc = get_loc ();
|
||||
const unsigned num = m_path->num_events ();
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
if (m_path->get_event (i).get_location () == loc)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
default_diagnostic_starter (diagnostic_context *context,
|
||||
diagnostic_info *diagnostic)
|
||||
|
||||
@@ -99,6 +99,38 @@ typedef void (*diagnostic_finalizer_fn) (diagnostic_context *,
|
||||
class edit_context;
|
||||
namespace json { class value; }
|
||||
|
||||
/* Abstract base class for printing diagnostic_paths, to isolate
|
||||
the path-printing code (which uses tree and thus is in OBJS) from the
|
||||
core diagnostic machinery (which is in OBJS-libcommon).
|
||||
|
||||
Concrete implementation is in tree-diagnostic-path.cc.
|
||||
|
||||
Implemented as a pair of calls, and thus as a pair of vfuncs, rather than
|
||||
a pair of callbacks.
|
||||
|
||||
This is done to allow -fdiagnostics-path-format=inline-events to
|
||||
consolidate and print less for, the common case where the path contains the
|
||||
rich_location, and hence the rich_location can be elided when it is
|
||||
redundant. */
|
||||
|
||||
class path_printer
|
||||
{
|
||||
public:
|
||||
static path_printer *make_tree_default ();
|
||||
virtual ~path_printer () {}
|
||||
|
||||
/* Vfunc called by diagnostic_show_locus: potentially print the path
|
||||
as inline events if the rest of the rich_location is redundant,
|
||||
returning true if this is the case. */
|
||||
virtual bool maybe_print_path_rather_than_richloc (diagnostic_context *,
|
||||
const rich_location &) = 0;
|
||||
|
||||
/* Vfunc called after the call to diagnostic_show_locus: print the path, if
|
||||
it wasn't printed already. */
|
||||
virtual void print_path (diagnostic_context *,
|
||||
const rich_location &) = 0;
|
||||
};
|
||||
|
||||
/* This data structure bundles altogether any information relevant to
|
||||
the context of a diagnostic message. */
|
||||
struct diagnostic_context
|
||||
@@ -232,8 +264,10 @@ struct diagnostic_context
|
||||
particular option. */
|
||||
char *(*get_option_url) (diagnostic_context *, int);
|
||||
|
||||
void (*print_path) (diagnostic_context *, const diagnostic_path *);
|
||||
json::value *(*make_json_for_path) (diagnostic_context *, const diagnostic_path *);
|
||||
/* Client hooks for working with diagnostic_paths. */
|
||||
path_printer *m_path_printer;
|
||||
json::value *(*make_json_for_path) (diagnostic_context *,
|
||||
const diagnostic_path *);
|
||||
|
||||
/* Auxiliary data for client. */
|
||||
void *x_data;
|
||||
|
||||
@@ -309,6 +309,7 @@ Objective-C and Objective-C++ Dialects}.
|
||||
-Wno-analyzer-tainted-array-index @gol
|
||||
-Wno-analyzer-unsafe-call-within-signal-handler @gol
|
||||
-Wno-analyzer-use-after-free @gol
|
||||
-Wno-analyzer-use-of-closed-file @gol
|
||||
-Wno-analyzer-use-of-pointer-in-stale-stack-frame @gol
|
||||
-Wno-analyzer-use-of-uninitialized-value @gol
|
||||
-Wanalyzer-too-complex @gol
|
||||
@@ -409,6 +410,7 @@ Objective-C and Objective-C++ Dialects}.
|
||||
-Wanalyzer-tainted-array-index @gol
|
||||
-Wanalyzer-unsafe-call-within-signal-handler @gol
|
||||
-Wanalyzer-use-after-free @gol
|
||||
-Wanalyzer-use-of-closed-file @gol
|
||||
-Wanalyzer-use-of-pointer-in-stale-stack-frame @gol
|
||||
-Wanalyzer-use-of-uninitialized-value @gol
|
||||
-Wanalyzer-too-complex @gol
|
||||
@@ -4209,27 +4211,24 @@ test.c:29:5: note: (3) when calling 'PyList_Append', passing NULL from (1) as ar
|
||||
@samp{inline-events} means to print the events ``inline'' within the source
|
||||
code. This view attempts to consolidate the events into runs of
|
||||
sufficiently-close events, printing them as labelled ranges within the source.
|
||||
|
||||
For example, the same events as above might be printed as:
|
||||
|
||||
@smallexample
|
||||
'test': events 1-3
|
||||
|
|
||||
| 25 | list = PyList_New(0);
|
||||
| | ^~~~~~~~~~~~~
|
||||
| | |
|
||||
| | (1) when 'PyList_New' fails, returning NULL
|
||||
| 26 |
|
||||
| 27 | for (i = 0; i < count; i++) @{
|
||||
| | ~~~
|
||||
| | |
|
||||
| | (2) when 'i < count'
|
||||
| 28 | item = PyLong_FromLong(random());
|
||||
| 29 | PyList_Append(list, item);
|
||||
| | ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
| | |
|
||||
| | (3) when calling 'PyList_Append', passing NULL from (1) as argument 1
|
||||
|
|
||||
test.c:29:5: error: passing NULL as argument 1 to 'PyList_Append' which requires a non-NULL parameter
|
||||
25 | list = PyList_New(0);
|
||||
| ^~~~~~~~~~~~~
|
||||
| |
|
||||
| (1) when 'PyList_New' fails, returning NULL
|
||||
26 |
|
||||
27 | for (i = 0; i < count; i++) @{
|
||||
| ~~~
|
||||
| |
|
||||
| (2) when 'i < count'
|
||||
28 | item = PyLong_FromLong(random());
|
||||
29 | PyList_Append(list, item);
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| (3) when calling 'PyList_Append', passing NULL from (1) as argument 1
|
||||
@end smallexample
|
||||
|
||||
Interprocedural control flow is shown by grouping the events by stack frame,
|
||||
@@ -4283,13 +4282,17 @@ For example:
|
||||
(etc)
|
||||
@end smallexample
|
||||
|
||||
If the location of the diagnostic is contained within the path and there are
|
||||
no fix-it hints or other complications, the source code for the location
|
||||
is elided and just the path is printed.
|
||||
|
||||
@item -fdiagnostics-show-path-depths
|
||||
@opindex fdiagnostics-show-path-depths
|
||||
This option provides additional information when printing control-flow paths
|
||||
associated with a diagnostic.
|
||||
|
||||
If this is option is provided then the stack depth will be printed for
|
||||
each run of events within @option{-fdiagnostics-path-format=separate-events}.
|
||||
each run of events within @option{-fdiagnostics-path-format=inline-events}.
|
||||
|
||||
This is intended for use by GCC developers and plugin developers when
|
||||
debugging diagnostics that report interprocedural control flow.
|
||||
@@ -6614,6 +6617,16 @@ This warning requires @option{-fanalyzer}, which enables it; use
|
||||
This diagnostic warns for paths through the code in which a
|
||||
pointer is used after @code{free} is called on it.
|
||||
|
||||
@item -Wno-analyzer-use-of-closed-file
|
||||
@opindex Wanalyzer-use-of-closed-file
|
||||
@opindex Wno-analyzer-use-of-closed-file
|
||||
This warning requires @option{-fanalyzer}, which enables it; use
|
||||
@option{-Wno-analyzer-use-of-closed-file} to disable it.
|
||||
|
||||
This diagnostic warns for paths through the code in which a
|
||||
@code{<stdio.h>} @code{FILE *} stream object is used after
|
||||
@code{fclose} is called on it.
|
||||
|
||||
@item -Wno-analyzer-use-of-pointer-in-stale-stack-frame
|
||||
@opindex Wanalyzer-use-of-pointer-in-stale-stack-frame
|
||||
@opindex Wno-analyzer-use-of-pointer-in-stale-stack-frame
|
||||
@@ -8329,6 +8342,7 @@ Enabling this option effectively enables the following warnings:
|
||||
-Wanalyzer-tainted-array-index @gol
|
||||
-Wanalyzer-unsafe-call-within-signal-handler @gol
|
||||
-Wanalyzer-use-after-free @gol
|
||||
-Wanalyzer-use-of-closed-file @gol
|
||||
-Wanalyzer-use-of-uninitialized-value @gol
|
||||
-Wanalyzer-use-of-pointer-in-stale-stack-frame @gol
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ void test_1 (void *ptr, int a, int b)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | free (ptr);
|
||||
| ^~~~~~~~~~
|
||||
'test_1': event 1
|
||||
|
|
||||
| NN | calls_free_1 (ptr);
|
||||
@@ -91,8 +89,6 @@ void test_2 (void *ptr, int a, int b)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | free (ptr);
|
||||
| ^~~~~~~~~~
|
||||
'test_2': event 1
|
||||
|
|
||||
| NN | calls_free_2 (ptr);
|
||||
@@ -148,16 +144,11 @@ void test_3 (void *ptr)
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | free (ptr);
|
||||
| ^~~~~~~~~~
|
||||
'test_3': events 1-2
|
||||
|
|
||||
| NN | free (ptr);
|
||||
| | ^~~~~~~~~~
|
||||
| | |
|
||||
| | (1) first 'free' here
|
||||
| NN | called_by_test_3 ();
|
||||
| NN | free (ptr);
|
||||
| | ~~~~~~~~~~
|
||||
| | |
|
||||
| | (2) second 'free' here; first 'free' was at (1)
|
||||
|
|
||||
| |
|
||||
| (1) first 'free' here
|
||||
NN | called_by_test_3 ();
|
||||
NN | free (ptr);
|
||||
| ~~~~~~~~~~
|
||||
| |
|
||||
| (2) second 'free' here; first 'free' was at (1)
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
@@ -21,8 +21,6 @@ void test_1 (void *ptr, int a, int b)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | free (ptr);
|
||||
| ^~~~~~~~~~
|
||||
'test_1': events 1-2
|
||||
|
|
||||
| NN | void test_1 (void *ptr, int a, int b)
|
||||
@@ -106,8 +104,6 @@ void test_2 (void *ptr, int a, int b)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | free (ptr);
|
||||
| ^~~~~~~~~~
|
||||
'test_2': events 1-2
|
||||
|
|
||||
| NN | void test_2 (void *ptr, int a, int b)
|
||||
@@ -176,16 +172,11 @@ void test_3 (void *ptr)
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | free (ptr);
|
||||
| ^~~~~~~~~~
|
||||
'test_3': events 1-2
|
||||
|
|
||||
| NN | free (ptr);
|
||||
| | ^~~~~~~~~~
|
||||
| | |
|
||||
| | (1) first 'free' here
|
||||
| NN | called_by_test_3 ();
|
||||
| NN | free (ptr);
|
||||
| | ~~~~~~~~~~
|
||||
| | |
|
||||
| | (2) second 'free' here; first 'free' was at (1)
|
||||
|
|
||||
| |
|
||||
| (1) first 'free' here
|
||||
NN | called_by_test_3 ();
|
||||
NN | free (ptr);
|
||||
| ~~~~~~~~~~
|
||||
| |
|
||||
| (2) second 'free' here; first 'free' was at (1)
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
@@ -21,8 +21,6 @@ void test_1 (void *ptr, int a, int b)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | free (ptr);
|
||||
| ^~~~~~~~~~
|
||||
'test_1': events 1-4
|
||||
|
|
||||
| NN | void test_1 (void *ptr, int a, int b)
|
||||
@@ -117,8 +115,6 @@ void test_2 (void *ptr, int a, int b)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | free (ptr);
|
||||
| ^~~~~~~~~~
|
||||
'test_2': events 1-4
|
||||
|
|
||||
| NN | void test_2 (void *ptr, int a, int b)
|
||||
@@ -207,16 +203,11 @@ void test_3 (void *ptr)
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | free (ptr);
|
||||
| ^~~~~~~~~~
|
||||
'test_3': events 1-2
|
||||
|
|
||||
| NN | free (ptr);
|
||||
| | ^~~~~~~~~~
|
||||
| | |
|
||||
| | (1) first 'free' here
|
||||
| NN | called_by_test_3 ();
|
||||
| NN | free (ptr);
|
||||
| | ~~~~~~~~~~
|
||||
| | |
|
||||
| | (2) second 'free' here; first 'free' was at (1)
|
||||
|
|
||||
| |
|
||||
| (1) first 'free' here
|
||||
NN | called_by_test_3 ();
|
||||
NN | free (ptr);
|
||||
| ~~~~~~~~~~
|
||||
| |
|
||||
| (2) second 'free' here; first 'free' was at (1)
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
@@ -47,3 +47,11 @@ test_4 (const char *path)
|
||||
|
||||
return; /* { dg-warning "leak of FILE 'f'" } */
|
||||
}
|
||||
|
||||
void
|
||||
test_5 (FILE *f, const char *msg)
|
||||
{
|
||||
fclose (f); /* { dg-message "\\(1\\) file closed here" } */
|
||||
fprintf (f, "foo: %s", msg); /* { dg-warning "use of closed FILE 'f'" } */
|
||||
/* { dg-message "\\(2\\) use of closed FILE 'f'; closed at \\(1\\)" "" { target *-*-* } .-1 } */
|
||||
}
|
||||
|
||||
@@ -29,8 +29,6 @@ void test (void *ptr)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | free (victim);
|
||||
| ^~~~~~~~~~~~~
|
||||
'test': events 1-2
|
||||
|
|
||||
| NN | void test (void *ptr)
|
||||
|
||||
@@ -47,8 +47,6 @@ void test (int i)
|
||||
|
||||
/* double-'free'. */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | free (ptr);
|
||||
| ^~~~~~~~~~
|
||||
'test': events 1-2
|
||||
|
|
||||
| NN | void test (int i)
|
||||
|
||||
@@ -25,8 +25,6 @@ make_boxed_int (int i)
|
||||
|
||||
/* "dereference of possibly-NULL 'result' [CWE-690]". */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | result->i = i;
|
||||
| ~~~~~~~~~~^~~
|
||||
'make_boxed_int': events 1-2
|
||||
|
|
||||
| NN | make_boxed_int (int i)
|
||||
|
||||
@@ -18,29 +18,21 @@ int test (void *ptr)
|
||||
/* { dg-regexp "\[^|\]+/malloc-macro.h:\[0-9\]+:\[0-9\]+:" } */
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
event 1
|
||||
|
||||
NN | #define WRAPPED_FREE(PTR) free(PTR)
|
||||
| ^~~~~~~~~
|
||||
| |
|
||||
| (1) first 'free' here
|
||||
NN | WRAPPED_FREE (ptr);
|
||||
| ^~~~~~~~~~~~
|
||||
event 2
|
||||
|
||||
NN | #define WRAPPED_FREE(PTR) free(PTR)
|
||||
| ^~~~~~~~~
|
||||
| |
|
||||
| (2) second 'free' here; first 'free' was at (1)
|
||||
NN | WRAPPED_FREE (ptr);
|
||||
| ^~~~~~~~~~~~
|
||||
'test': event 1
|
||||
|
|
||||
|
|
||||
| NN | #define WRAPPED_FREE(PTR) free(PTR)
|
||||
| | ^~~~~~~~~
|
||||
| | |
|
||||
| | (1) first 'free' here
|
||||
| NN | WRAPPED_FREE (ptr);
|
||||
| | ^~~~~~~~~~~~
|
||||
|
|
||||
'test': event 2
|
||||
|
|
||||
|
|
||||
| NN | #define WRAPPED_FREE(PTR) free(PTR)
|
||||
| | ^~~~~~~~~
|
||||
| | |
|
||||
| | (2) second 'free' here; first 'free' was at (1)
|
||||
| NN | WRAPPED_FREE (ptr);
|
||||
| | ^~~~~~~~~~~~
|
||||
|
|
||||
{ dg-end-multiline-output "" } */
|
||||
}
|
||||
|
||||
@@ -10,23 +10,18 @@ void test_1 (void)
|
||||
free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
|
||||
}
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | void *ptr = malloc (1024);
|
||||
| ^~~~~~~~~~~~~
|
||||
| |
|
||||
| (1) allocated here
|
||||
NN | free (ptr);
|
||||
| ^~~~~~~~~~
|
||||
'test_1': events 1-3
|
||||
|
|
||||
| NN | void *ptr = malloc (1024);
|
||||
| | ^~~~~~~~~~~~~
|
||||
| | |
|
||||
| | (1) allocated here
|
||||
| NN | free (ptr);
|
||||
| | ~~~~~~~~~~
|
||||
| | |
|
||||
| | (2) first 'free' here
|
||||
| NN | free (ptr);
|
||||
| | ~~~~~~~~~~
|
||||
| | |
|
||||
| | (3) second 'free' here; first 'free' was at (2)
|
||||
|
|
||||
| ~~~~~~~~~~
|
||||
| |
|
||||
| (2) first 'free' here
|
||||
NN | free (ptr);
|
||||
| ~~~~~~~~~~
|
||||
| |
|
||||
| (3) second 'free' here; first 'free' was at (2)
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
void test_2 (int x, int y)
|
||||
@@ -40,62 +35,52 @@ void test_2 (int x, int y)
|
||||
|
||||
/* "double-'free' of 'ptr'". */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | void *ptr = malloc (1024);
|
||||
| ^~~~~~~~~~~~~
|
||||
| |
|
||||
| (1) allocated here
|
||||
NN | if (x)
|
||||
| ~
|
||||
| |
|
||||
| (2) following 'true' branch (when 'x != 0')...
|
||||
NN | free (ptr);
|
||||
| ^~~~~~~~~~
|
||||
'test_2': events 1-7
|
||||
|
|
||||
| NN | void *ptr = malloc (1024);
|
||||
| | ^~~~~~~~~~~~~
|
||||
| | |
|
||||
| | (1) allocated here
|
||||
| NN | if (x)
|
||||
| | ~
|
||||
| | |
|
||||
| | (2) following 'true' branch (when 'x != 0')...
|
||||
| NN | free (ptr);
|
||||
| | ~~~~~~~~~~
|
||||
| | |
|
||||
| | (3) ...to here
|
||||
| | (4) first 'free' here
|
||||
| NN | if (y)
|
||||
| | ~
|
||||
| | |
|
||||
| | (5) following 'true' branch (when 'y != 0')...
|
||||
| NN | free (ptr);
|
||||
| | ~~~~~~~~~~
|
||||
| | |
|
||||
| | (6) ...to here
|
||||
| | (7) second 'free' here; first 'free' was at (4)
|
||||
|
|
||||
| ~~~~~~~~~~
|
||||
| |
|
||||
| (3) ...to here
|
||||
| (4) first 'free' here
|
||||
NN | if (y)
|
||||
| ~
|
||||
| |
|
||||
| (5) following 'true' branch (when 'y != 0')...
|
||||
NN | free (ptr);
|
||||
| ~~~~~~~~~~
|
||||
| |
|
||||
| (6) ...to here
|
||||
| (7) second 'free' here; first 'free' was at (4)
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
/* "leak of 'ptr'. */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | void *ptr = malloc (1024);
|
||||
| ^~~~~~~~~~~~~
|
||||
| |
|
||||
| (1) allocated here
|
||||
NN | if (x)
|
||||
| ~
|
||||
| |
|
||||
| (2) following 'false' branch (when 'x == 0')...
|
||||
NN | free (ptr);
|
||||
NN | if (y)
|
||||
| ~
|
||||
| |
|
||||
| (3) ...to here
|
||||
| (4) following 'false' branch (when 'y == 0')...
|
||||
NN | free (ptr);
|
||||
NN | }
|
||||
| ^
|
||||
'test_2': events 1-6
|
||||
|
|
||||
| NN | void *ptr = malloc (1024);
|
||||
| | ^~~~~~~~~~~~~
|
||||
| | |
|
||||
| | (1) allocated here
|
||||
| NN | if (x)
|
||||
| | ~
|
||||
| | |
|
||||
| | (2) following 'false' branch (when 'x == 0')...
|
||||
| NN | free (ptr);
|
||||
| NN | if (y)
|
||||
| | ~
|
||||
| | |
|
||||
| | (3) ...to here
|
||||
| | (4) following 'false' branch (when 'y == 0')...
|
||||
| NN | free (ptr);
|
||||
| NN | }
|
||||
| | ~
|
||||
| | |
|
||||
| | (5) ...to here
|
||||
| | (6) 'ptr' leaks here; was allocated at (1)
|
||||
|
|
||||
| ~
|
||||
| |
|
||||
| (5) ...to here
|
||||
| (6) 'ptr' leaks here; was allocated at (1)
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
int test_3 (int x, int y)
|
||||
@@ -118,182 +103,152 @@ int test_3 (int x, int y)
|
||||
|
||||
/* "dereference of possibly-NULL 'ptr'". */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | int *ptr = (int *)malloc (sizeof (int));
|
||||
| ^~~~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| (1) this call could return NULL
|
||||
NN | *ptr = 42;
|
||||
| ~~~~~^~~~
|
||||
'test_3': events 1-2
|
||||
|
|
||||
| NN | int *ptr = (int *)malloc (sizeof (int));
|
||||
| | ^~~~~~~~~~~~~~~~~~~~~
|
||||
| | |
|
||||
| | (1) this call could return NULL
|
||||
| NN | *ptr = 42;
|
||||
| | ~~~~~~~~~
|
||||
| | |
|
||||
| | (2) 'ptr' could be NULL: unchecked value from (1)
|
||||
|
|
||||
| ~~~~~~~~~
|
||||
| |
|
||||
| (2) 'ptr' could be NULL: unchecked value from (1)
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
/* "use after 'free' of 'ptr'". */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | int *ptr = (int *)malloc (sizeof (int));
|
||||
| ^~~~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| (1) allocated here
|
||||
NN | *ptr = 42;
|
||||
| ~~~~~~~~~
|
||||
| |
|
||||
| (2) assuming 'ptr' is non-NULL
|
||||
NN | if (x)
|
||||
| ~
|
||||
| |
|
||||
| (3) following 'true' branch (when 'x != 0')...
|
||||
NN | free (ptr);
|
||||
| ~~~~~~~~~~
|
||||
| |
|
||||
| (4) ...to here
|
||||
| (5) freed here
|
||||
NN |
|
||||
NN | *ptr = 19;
|
||||
| ~~~~~^~~~
|
||||
'test_3': events 1-6
|
||||
|
|
||||
| NN | int *ptr = (int *)malloc (sizeof (int));
|
||||
| | ^~~~~~~~~~~~~~~~~~~~~
|
||||
| | |
|
||||
| | (1) allocated here
|
||||
| NN | *ptr = 42;
|
||||
| | ~~~~~~~~~
|
||||
| | |
|
||||
| | (2) assuming 'ptr' is non-NULL
|
||||
| NN | if (x)
|
||||
| | ~
|
||||
| | |
|
||||
| | (3) following 'true' branch (when 'x != 0')...
|
||||
| NN | free (ptr);
|
||||
| | ~~~~~~~~~~
|
||||
| | |
|
||||
| | (4) ...to here
|
||||
| | (5) freed here
|
||||
| NN |
|
||||
| NN | *ptr = 19;
|
||||
| | ~~~~~~~~~
|
||||
| | |
|
||||
| | (6) use after 'free' of 'ptr'; freed at (5)
|
||||
|
|
||||
| ~~~~~~~~~
|
||||
| |
|
||||
| (6) use after 'free' of 'ptr'; freed at (5)
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
/* "use after 'free' of 'ptr'". */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | int *ptr = (int *)malloc (sizeof (int));
|
||||
| ^~~~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| (1) allocated here
|
||||
NN | *ptr = 42;
|
||||
| ~~~~~~~~~
|
||||
| |
|
||||
| (2) assuming 'ptr' is non-NULL
|
||||
NN | if (x)
|
||||
| ~
|
||||
| |
|
||||
| (3) following 'false' branch (when 'x == 0')...
|
||||
......
|
||||
NN | *ptr = 19;
|
||||
| ~~~~~~~~~
|
||||
| |
|
||||
| (4) ...to here
|
||||
......
|
||||
NN | if (y)
|
||||
| ~
|
||||
| |
|
||||
| (5) following 'true' branch (when 'y != 0')...
|
||||
NN | free (ptr);
|
||||
| ~~~~~~~~~~
|
||||
| |
|
||||
| (6) ...to here
|
||||
| (7) freed here
|
||||
NN |
|
||||
NN | return *ptr;
|
||||
| ^~~~
|
||||
'test_3': events 1-8
|
||||
|
|
||||
| NN | int *ptr = (int *)malloc (sizeof (int));
|
||||
| | ^~~~~~~~~~~~~~~~~~~~~
|
||||
| | |
|
||||
| | (1) allocated here
|
||||
| NN | *ptr = 42;
|
||||
| | ~~~~~~~~~
|
||||
| | |
|
||||
| | (2) assuming 'ptr' is non-NULL
|
||||
| NN | if (x)
|
||||
| | ~
|
||||
| | |
|
||||
| | (3) following 'false' branch (when 'x == 0')...
|
||||
|......
|
||||
| NN | *ptr = 19;
|
||||
| | ~~~~~~~~~
|
||||
| | |
|
||||
| | (4) ...to here
|
||||
|......
|
||||
| NN | if (y)
|
||||
| | ~
|
||||
| | |
|
||||
| | (5) following 'true' branch (when 'y != 0')...
|
||||
| NN | free (ptr);
|
||||
| | ~~~~~~~~~~
|
||||
| | |
|
||||
| | (6) ...to here
|
||||
| | (7) freed here
|
||||
| NN |
|
||||
| NN | return *ptr;
|
||||
| | ~~~~
|
||||
| | |
|
||||
| | (8) use after 'free' of 'ptr'; freed at (7)
|
||||
|
|
||||
| ~~~~
|
||||
| |
|
||||
| (8) use after 'free' of 'ptr'; freed at (7)
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
/* "leak of 'ptr'". */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | return *ptr;
|
||||
| ^~~~
|
||||
'test_3': events 1-7
|
||||
|
|
||||
| NN | int *ptr = (int *)malloc (sizeof (int));
|
||||
| | ^~~~~~~~~~~~~~~~~~~~~
|
||||
| | |
|
||||
| | (1) allocated here
|
||||
| NN | *ptr = 42;
|
||||
| | ~~~~~~~~~
|
||||
| | |
|
||||
| | (2) assuming 'ptr' is non-NULL
|
||||
| NN | if (x)
|
||||
| | ~
|
||||
| | |
|
||||
| | (3) following 'false' branch (when 'x == 0')...
|
||||
|......
|
||||
| NN | *ptr = 19;
|
||||
| | ~~~~~~~~~
|
||||
| | |
|
||||
| | (4) ...to here
|
||||
|......
|
||||
| NN | if (y)
|
||||
| | ~
|
||||
| | |
|
||||
| | (5) following 'false' branch (when 'y == 0')...
|
||||
|......
|
||||
| NN | return *ptr;
|
||||
| | ~~~~
|
||||
| | |
|
||||
| | (6) ...to here
|
||||
| | (7) 'ptr' leaks here; was allocated at (1)
|
||||
|
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
/* "use after 'free' of 'ptr'". */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | int *ptr = (int *)malloc (sizeof (int));
|
||||
| ^~~~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| (1) allocated here
|
||||
NN | *ptr = 42;
|
||||
| ~~~~~~~~~
|
||||
| |
|
||||
| (2) assuming 'ptr' is non-NULL
|
||||
NN | if (x)
|
||||
| ~
|
||||
| |
|
||||
| (3) following 'false' branch (when 'x == 0')...
|
||||
......
|
||||
NN | *ptr = 19;
|
||||
| ~~~~~^~~~
|
||||
'test_3': events 1-3
|
||||
|
|
||||
| NN | if (x)
|
||||
| | ^
|
||||
| | |
|
||||
| | (1) following 'true' branch (when 'x != 0')...
|
||||
| NN | free (ptr);
|
||||
| | ~~~~~~~~~~
|
||||
| | |
|
||||
| | (2) ...to here
|
||||
| NN |
|
||||
| NN | *ptr = 19;
|
||||
| | ~~~~~~~~~
|
||||
| | |
|
||||
| | (3) use after 'free' of 'ptr' here
|
||||
|
|
||||
| ~~~~~~~~~
|
||||
| |
|
||||
| (4) ...to here
|
||||
......
|
||||
NN | if (y)
|
||||
| ~
|
||||
| |
|
||||
| (5) following 'false' branch (when 'y == 0')...
|
||||
......
|
||||
NN | return *ptr;
|
||||
| ~~~~
|
||||
| |
|
||||
| (6) ...to here
|
||||
| (7) 'ptr' leaks here; was allocated at (1)
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
/* "use after 'free' of 'ptr'". */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | if (x)
|
||||
| ^
|
||||
| |
|
||||
| (1) following 'true' branch (when 'x != 0')...
|
||||
NN | free (ptr);
|
||||
| ~~~~~~~~~~
|
||||
| |
|
||||
| (2) ...to here
|
||||
NN |
|
||||
NN | *ptr = 19;
|
||||
| ~~~~~~~~~
|
||||
| |
|
||||
| (3) use after 'free' of 'ptr' here
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
/* "use after 'free' of 'ptr'". */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | if (x)
|
||||
| ^
|
||||
| |
|
||||
| (1) following 'false' branch (when 'x == 0')...
|
||||
......
|
||||
NN | *ptr = 19;
|
||||
| ~~~~~~~~~
|
||||
| |
|
||||
| (2) ...to here
|
||||
......
|
||||
NN | if (y)
|
||||
| ~
|
||||
| |
|
||||
| (3) following 'true' branch (when 'y != 0')...
|
||||
NN | free (ptr);
|
||||
| ~~~~~~~~~~
|
||||
| |
|
||||
| (4) ...to here
|
||||
NN | to dereference it above
|
||||
NN | return *ptr;
|
||||
| ^~~~
|
||||
'test_3': events 1-5
|
||||
|
|
||||
| NN | if (x)
|
||||
| | ^
|
||||
| | |
|
||||
| | (1) following 'false' branch (when 'x == 0')...
|
||||
|......
|
||||
| NN | *ptr = 19;
|
||||
| | ~~~~~~~~~
|
||||
| | |
|
||||
| | (2) ...to here
|
||||
|......
|
||||
| NN | if (y)
|
||||
| | ~
|
||||
| | |
|
||||
| | (3) following 'true' branch (when 'y != 0')...
|
||||
| NN | free (ptr);
|
||||
| | ~~~~~~~~~~
|
||||
| | |
|
||||
| | (4) ...to here
|
||||
| NN | to dereference it above
|
||||
| NN | return *ptr;
|
||||
| | ~~~~
|
||||
| | |
|
||||
| | (5) use after 'free' of 'ptr' here
|
||||
|
|
||||
| ~~~~
|
||||
| |
|
||||
| (5) use after 'free' of 'ptr' here
|
||||
{ dg-end-multiline-output "" } */
|
||||
/* TODO: this is really a duplicate; can we either eliminate it, or
|
||||
improve the path? */
|
||||
|
||||
@@ -35,51 +35,41 @@ void test_2 (void)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
event 1
|
||||
NN | i = setjmp(env);
|
||||
| ^~~~~~
|
||||
| |
|
||||
| (1) 'setjmp' called here
|
||||
events 2-4
|
||||
NN | if (i != 0)
|
||||
| ^
|
||||
| |
|
||||
| (2) following 'false' branch (when 'i == 0')...
|
||||
......
|
||||
NN | longjmp (env, 1);
|
||||
| ~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| (3) ...to here
|
||||
| (4) rewinding within 'test_2' from 'longjmp'...
|
||||
event 5
|
||||
NN | i = setjmp(env);
|
||||
| ^~~~~~
|
||||
| |
|
||||
| (5) ...to 'setjmp' (saved at (1))
|
||||
events 6-8
|
||||
NN | if (i != 0)
|
||||
| ^
|
||||
| |
|
||||
| (6) following 'true' branch (when 'i != 0')...
|
||||
NN | {
|
||||
NN | foo (2);
|
||||
| ~~~~~~~
|
||||
| |
|
||||
| (7) ...to here
|
||||
NN | __analyzer_dump_path ();
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~
|
||||
'test_2': event 1
|
||||
|
|
||||
| NN | i = setjmp(env);
|
||||
| | ^~~~~~
|
||||
| | |
|
||||
| | (1) 'setjmp' called here
|
||||
|
|
||||
'test_2': events 2-4
|
||||
|
|
||||
| NN | if (i != 0)
|
||||
| | ^
|
||||
| | |
|
||||
| | (2) following 'false' branch (when 'i == 0')...
|
||||
|......
|
||||
| NN | longjmp (env, 1);
|
||||
| | ~~~~~~~~~~~~~~~~
|
||||
| | |
|
||||
| | (3) ...to here
|
||||
| | (4) rewinding within 'test_2' from 'longjmp'...
|
||||
|
|
||||
'test_2': event 5
|
||||
|
|
||||
| NN | i = setjmp(env);
|
||||
| | ^~~~~~
|
||||
| | |
|
||||
| | (5) ...to 'setjmp' (saved at (1))
|
||||
|
|
||||
'test_2': events 6-8
|
||||
|
|
||||
| NN | if (i != 0)
|
||||
| | ^
|
||||
| | |
|
||||
| | (6) following 'true' branch (when 'i != 0')...
|
||||
| NN | {
|
||||
| NN | foo (2);
|
||||
| | ~~~~~~~
|
||||
| | |
|
||||
| | (7) ...to here
|
||||
| NN | __analyzer_dump_path ();
|
||||
| | ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
| | |
|
||||
| | (8) here
|
||||
|
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| (8) here
|
||||
{ dg-end-multiline-output "" } */
|
||||
|
||||
void test_3 (void)
|
||||
|
||||
@@ -36,8 +36,6 @@ void outer (void)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | __analyzer_dump_path ();
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~
|
||||
'outer': event 1
|
||||
|
|
||||
| NN | void outer (void)
|
||||
|
||||
@@ -31,8 +31,6 @@ int main (void)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | __analyzer_dump_path ();
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~
|
||||
'main': event 1
|
||||
|
|
||||
| NN | int main (void)
|
||||
|
||||
@@ -22,8 +22,6 @@ void outer (void)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | longjmp (env, 42);
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
'outer': events 1-2
|
||||
|
|
||||
| NN | void outer (void)
|
||||
|
||||
@@ -38,8 +38,6 @@ void outer (void)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | longjmp (env, 1);
|
||||
| ^~~~~~~~~~~~~~~~
|
||||
'outer': event 1
|
||||
|
|
||||
| NN | void outer (void)
|
||||
|
||||
@@ -37,8 +37,6 @@ void outer (void)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | __analyzer_dump_path ();
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~
|
||||
'outer': event 1
|
||||
|
|
||||
| NN | void outer (void)
|
||||
|
||||
@@ -39,8 +39,6 @@ void outer (void)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | __analyzer_dump_path ();
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~
|
||||
'outer': event 1
|
||||
|
|
||||
| NN | void outer (void)
|
||||
|
||||
@@ -29,8 +29,6 @@ void test (void)
|
||||
|
||||
/* "call to 'fprintf' from within signal handler [CWE-479]". */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | fprintf(stderr, "LOG: %s", msg);
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
'test': events 1-2
|
||||
|
|
||||
| NN | void test (void)
|
||||
|
||||
@@ -32,8 +32,6 @@ void test (void)
|
||||
|
||||
/* "call to 'fprintf' from within signal handler [CWE-479]". */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | fprintf(stderr, "LOG: %s", msg);
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
'test': events 1-2
|
||||
|
|
||||
| NN | void test (void)
|
||||
|
||||
@@ -12,8 +12,6 @@ void wrapped_free (void *ptr)
|
||||
{
|
||||
free (ptr); /* { dg-warning "double-free of 'ptr' \\\[CWE-415\\]" } */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
free (ptr);
|
||||
^~~~~~~~~~
|
||||
'test': events 1-2
|
||||
|
|
||||
| {
|
||||
|
||||
@@ -12,8 +12,6 @@ void wrapped_free (void *ptr)
|
||||
{
|
||||
free (ptr); /* { dg-warning "double-free of 'ptr' \\\[CWE-415\\]" } */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
free (ptr);
|
||||
^~~~~~~~~~
|
||||
'test': events 1-2
|
||||
|
|
||||
| {
|
||||
|
||||
@@ -17,8 +17,6 @@ void wrapped_free (void *ptr)
|
||||
{
|
||||
free (ptr); /* { dg-warning "double-free of 'ptr' \\\[CWE-415\\]" } */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
free (ptr);
|
||||
^~~~~~~~~~
|
||||
'test': events 1-2
|
||||
|
|
||||
| {
|
||||
|
||||
@@ -17,8 +17,6 @@ void wrapped_free (void *ptr)
|
||||
{
|
||||
free (ptr); /* { dg-warning "double-free of 'ptr' \\\[CWE-415\\]" } */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | free (ptr);
|
||||
| ^~~~~~~~~~
|
||||
'test': events 1-2
|
||||
|
|
||||
| NN | {
|
||||
|
||||
@@ -33,24 +33,19 @@ make_a_list_of_random_ints_badly(PyObject *self,
|
||||
|
||||
/* { dg-error "passing NULL as argument 1 to 'PyList_Append' which requires a non-NULL parameter" "" { target *-*-* } PyList_Append } */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
25 | list = PyList_New(0);
|
||||
| ^~~~~~~~~~~~~
|
||||
| |
|
||||
| (1) when 'PyList_New' fails, returning NULL
|
||||
26 |
|
||||
27 | for (i = 0; i < count; i++) {
|
||||
| ~~~
|
||||
| |
|
||||
| (2) when 'i < count'
|
||||
28 | item = PyLong_FromLong(random());
|
||||
29 | PyList_Append(list, item);
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
'make_a_list_of_random_ints_badly': events 1-3
|
||||
|
|
||||
| 25 | list = PyList_New(0);
|
||||
| | ^~~~~~~~~~~~~
|
||||
| | |
|
||||
| | (1) when 'PyList_New' fails, returning NULL
|
||||
| 26 |
|
||||
| 27 | for (i = 0; i < count; i++) {
|
||||
| | ~~~
|
||||
| | |
|
||||
| | (2) when 'i < count'
|
||||
| 28 | item = PyLong_FromLong(random());
|
||||
| 29 | PyList_Append(list, item);
|
||||
| | ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
| | |
|
||||
| | (3) when calling 'PyList_Append', passing NULL from (1) as argument 1
|
||||
|
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| (3) when calling 'PyList_Append', passing NULL from (1) as argument 1
|
||||
{ dg-end-multiline-output "" } */
|
||||
}
|
||||
|
||||
58
gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-2a.c
Normal file
58
gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-2a.c
Normal file
@@ -0,0 +1,58 @@
|
||||
/* Example of a path that can't elide its richloc, due to a label. */
|
||||
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers -fplugin-arg-diagnostic_plugin_test_paths-dummy_label" } */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Minimal reimplementation of cpython API. */
|
||||
typedef struct PyObject {} PyObject;
|
||||
extern int PyArg_ParseTuple (PyObject *args, const char *fmt, ...);
|
||||
extern PyObject *PyList_New (int);
|
||||
extern PyObject *PyLong_FromLong(long);
|
||||
extern void PyList_Append(PyObject *list, PyObject *item);
|
||||
|
||||
PyObject *
|
||||
make_a_list_of_random_ints_badly (PyObject *self,
|
||||
PyObject *args)
|
||||
{
|
||||
PyObject *list, *item;
|
||||
long count, i;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i", &count)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list = PyList_New(0); /* { dg-line PyList_New } */
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
item = PyLong_FromLong(random());
|
||||
PyList_Append(list, item); /* { dg-line PyList_Append } */
|
||||
}
|
||||
|
||||
return list;
|
||||
|
||||
/* { dg-error "passing NULL as argument 1 to 'PyList_Append' which requires a non-NULL parameter" "" { target *-*-* } PyList_Append } */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
31 | PyList_Append(list, item);
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| dummy label
|
||||
events 1-3
|
||||
27 | list = PyList_New(0);
|
||||
| ^~~~~~~~~~~~~
|
||||
| |
|
||||
| (1) when 'PyList_New' fails, returning NULL
|
||||
28 |
|
||||
29 | for (i = 0; i < count; i++) {
|
||||
| ~~~
|
||||
| |
|
||||
| (2) when 'i < count'
|
||||
30 | item = PyLong_FromLong(random());
|
||||
31 | PyList_Append(list, item);
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| (3) when calling 'PyList_Append', passing NULL from (1) as argument 1
|
||||
{ dg-end-multiline-output "" } */
|
||||
}
|
||||
@@ -30,8 +30,6 @@ void test (void)
|
||||
}
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
NN | fprintf(stderr, "LOG: %s", msg);
|
||||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
'test': events 1-2
|
||||
|
|
||||
| NN | {
|
||||
|
||||
@@ -57,7 +57,7 @@ const pass_data pass_data_test_show_path =
|
||||
class pass_test_show_path : public ipa_opt_pass_d
|
||||
{
|
||||
public:
|
||||
pass_test_show_path(gcc::context *ctxt)
|
||||
pass_test_show_path(gcc::context *ctxt, bool dummy_label)
|
||||
: ipa_opt_pass_d (pass_data_test_show_path, ctxt,
|
||||
NULL, /* generate_summary */
|
||||
NULL, /* write_summary */
|
||||
@@ -67,13 +67,16 @@ public:
|
||||
NULL, /* stmt_fixup */
|
||||
0, /* function_transform_todo_flags_start */
|
||||
NULL, /* function_transform */
|
||||
NULL) /* variable_transform */
|
||||
NULL), /* variable_transform */
|
||||
m_dummy_label (dummy_label)
|
||||
{}
|
||||
|
||||
/* opt_pass methods: */
|
||||
bool gate (function *) { return true; }
|
||||
virtual unsigned int execute (function *);
|
||||
|
||||
bool m_dummy_label;
|
||||
|
||||
}; // class pass_test_show_path
|
||||
|
||||
/* Determine if STMT is a call with NUM_ARGS arguments to a function
|
||||
@@ -110,7 +113,7 @@ check_for_named_call (gimple *stmt,
|
||||
/* Example 1: a purely intraprocedural path. */
|
||||
|
||||
static void
|
||||
example_1 ()
|
||||
example_1 (bool dummy_label)
|
||||
{
|
||||
gimple_stmt_iterator gsi;
|
||||
basic_block bb;
|
||||
@@ -146,6 +149,13 @@ example_1 ()
|
||||
{
|
||||
auto_diagnostic_group d;
|
||||
gcc_rich_location richloc (gimple_location (call_to_PyList_Append));
|
||||
|
||||
text_range_label label ("dummy label");
|
||||
if (dummy_label)
|
||||
richloc.add_range (gimple_location (call_to_PyList_Append),
|
||||
SHOW_RANGE_WITHOUT_CARET,
|
||||
&label);
|
||||
|
||||
simple_diagnostic_path path (global_dc->printer);
|
||||
diagnostic_event_id_t alloc_event_id
|
||||
= path.add_event (gimple_location (call_to_PyList_New),
|
||||
@@ -424,19 +434,13 @@ example_3 ()
|
||||
unsigned int
|
||||
pass_test_show_path::execute (function *)
|
||||
{
|
||||
example_1 ();
|
||||
example_1 (m_dummy_label);
|
||||
example_2 ();
|
||||
example_3 ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static opt_pass *
|
||||
make_pass_test_show_path (gcc::context *ctxt)
|
||||
{
|
||||
return new pass_test_show_path (ctxt);
|
||||
}
|
||||
|
||||
int
|
||||
plugin_init (struct plugin_name_args *plugin_info,
|
||||
struct plugin_gcc_version *version)
|
||||
@@ -449,7 +453,14 @@ plugin_init (struct plugin_name_args *plugin_info,
|
||||
if (!plugin_default_version_check (version, &gcc_version))
|
||||
return 1;
|
||||
|
||||
pass_info.pass = make_pass_test_show_path (g);
|
||||
bool dummy_label = false;
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
if (strcmp (argv[i].key, "dummy_label") == 0)
|
||||
dummy_label = true;
|
||||
}
|
||||
|
||||
pass_info.pass = new pass_test_show_path (g, dummy_label);
|
||||
pass_info.reference_pass_name = "whole-program";
|
||||
pass_info.ref_pass_instance_number = 1;
|
||||
pass_info.pos_op = PASS_POS_INSERT_BEFORE;
|
||||
|
||||
@@ -98,6 +98,7 @@ set plugin_test_list [list \
|
||||
{ diagnostic_plugin_test_paths.c \
|
||||
diagnostic-test-paths-1.c \
|
||||
diagnostic-test-paths-2.c \
|
||||
diagnostic-test-paths-2a.c \
|
||||
diagnostic-test-paths-3.c \
|
||||
diagnostic-test-paths-4.c \
|
||||
diagnostic-path-format-default.c \
|
||||
|
||||
@@ -211,11 +211,13 @@ class path_summary
|
||||
public:
|
||||
path_summary (const diagnostic_path &path, bool check_rich_locations);
|
||||
|
||||
void print (diagnostic_context *dc, bool show_depths) const;
|
||||
void print (diagnostic_context *dc, bool show_depths,
|
||||
bool need_event_header = true) const;
|
||||
|
||||
unsigned get_num_ranges () const { return m_ranges.length (); }
|
||||
|
||||
private:
|
||||
const diagnostic_path &m_path;
|
||||
auto_delete_vec <event_range> m_ranges;
|
||||
};
|
||||
|
||||
@@ -223,6 +225,7 @@ class path_summary
|
||||
|
||||
path_summary::path_summary (const diagnostic_path &path,
|
||||
bool check_rich_locations)
|
||||
: m_path (path)
|
||||
{
|
||||
const unsigned num_events = path.num_events ();
|
||||
|
||||
@@ -272,34 +275,42 @@ print_fndecl (pretty_printer *pp, tree fndecl, bool quoted)
|
||||
descriptions within calls to diagnostic_show_locus, using labels to
|
||||
show the events:
|
||||
|
||||
'foo' (events 1-2)
|
||||
'foo': events 1-2
|
||||
| NN |
|
||||
| |
|
||||
+--> 'bar' (events 3-4)
|
||||
+--> 'bar': events 3-4
|
||||
| NN |
|
||||
| |
|
||||
+--> 'baz' (events 5-6)
|
||||
+--> 'baz': events 5-6
|
||||
| NN |
|
||||
| |
|
||||
<------------ +
|
||||
|
|
||||
'foo' (events 7-8)
|
||||
'foo': events 7-8
|
||||
| NN |
|
||||
| |
|
||||
+--> 'bar' (events 9-10)
|
||||
+--> 'bar': events 9-10
|
||||
| NN |
|
||||
| |
|
||||
+--> 'baz' (events 11-12)
|
||||
+--> 'baz': events 11-12
|
||||
| NN |
|
||||
| |
|
||||
|
||||
If SHOW_DEPTHS is true, append " (depth N)" to the header of each run
|
||||
of events.
|
||||
|
||||
For events with UNKNOWN_LOCATION, print a summary of each the event. */
|
||||
For events with UNKNOWN_LOCATION, print a summary of each the event.
|
||||
|
||||
If the path is purely intraprocedural, don't print the function name
|
||||
or the left-hand stack-depth lines.
|
||||
|
||||
If NEED_EVENT_HEADER is true, then a header is printed for every run
|
||||
of events. Otherwise, headers are only printed if there is more than
|
||||
one run of events. */
|
||||
|
||||
void
|
||||
path_summary::print (diagnostic_context *dc, bool show_depths) const
|
||||
path_summary::print (diagnostic_context *dc, bool show_depths,
|
||||
bool need_event_header) const
|
||||
{
|
||||
pretty_printer *pp = dc->printer;
|
||||
|
||||
@@ -317,6 +328,8 @@ path_summary::print (diagnostic_context *dc, bool show_depths) const
|
||||
typedef int_hash <int, EMPTY, DELETED> vbar_hash;
|
||||
hash_map <vbar_hash, int> vbar_column_for_depth;
|
||||
|
||||
const bool interprocedural = m_path.interprocedural_p ();
|
||||
|
||||
/* Print the ranges. */
|
||||
const int base_indent = 2;
|
||||
int cur_indent = base_indent;
|
||||
@@ -324,67 +337,77 @@ path_summary::print (diagnostic_context *dc, bool show_depths) const
|
||||
event_range *range;
|
||||
FOR_EACH_VEC_ELT (m_ranges, i, range)
|
||||
{
|
||||
write_indent (pp, cur_indent);
|
||||
if (i > 0)
|
||||
/* Write the header line for a run of events. */
|
||||
if (m_ranges.length () > 1 || need_event_header)
|
||||
{
|
||||
const path_summary::event_range *prev_range
|
||||
= m_ranges[i - 1];
|
||||
if (range->m_stack_depth > prev_range->m_stack_depth)
|
||||
write_indent (pp, cur_indent);
|
||||
if (i > 0)
|
||||
{
|
||||
/* Show pushed stack frame(s). */
|
||||
const char *push_prefix = "+--> ";
|
||||
pp_string (pp, start_line_color);
|
||||
pp_string (pp, push_prefix);
|
||||
pp_string (pp, end_line_color);
|
||||
cur_indent += strlen (push_prefix);
|
||||
const path_summary::event_range *prev_range
|
||||
= m_ranges[i - 1];
|
||||
if (range->m_stack_depth > prev_range->m_stack_depth)
|
||||
{
|
||||
/* Show pushed stack frame(s). */
|
||||
const char *push_prefix = "+--> ";
|
||||
pp_string (pp, start_line_color);
|
||||
pp_string (pp, push_prefix);
|
||||
pp_string (pp, end_line_color);
|
||||
cur_indent += strlen (push_prefix);
|
||||
}
|
||||
}
|
||||
if (interprocedural && range->m_fndecl)
|
||||
{
|
||||
print_fndecl (pp, range->m_fndecl, true);
|
||||
pp_string (pp, ": ");
|
||||
}
|
||||
if (range->m_start_idx == range->m_end_idx)
|
||||
pp_printf (pp, "event %i",
|
||||
range->m_start_idx + 1);
|
||||
else
|
||||
pp_printf (pp, "events %i-%i",
|
||||
range->m_start_idx + 1, range->m_end_idx + 1);
|
||||
if (show_depths)
|
||||
pp_printf (pp, " (depth %i)", range->m_stack_depth);
|
||||
pp_newline (pp);
|
||||
}
|
||||
if (range->m_fndecl)
|
||||
{
|
||||
print_fndecl (pp, range->m_fndecl, true);
|
||||
pp_string (pp, ": ");
|
||||
}
|
||||
if (range->m_start_idx == range->m_end_idx)
|
||||
pp_printf (pp, "event %i",
|
||||
range->m_start_idx + 1);
|
||||
else
|
||||
pp_printf (pp, "events %i-%i",
|
||||
range->m_start_idx + 1, range->m_end_idx + 1);
|
||||
if (show_depths)
|
||||
pp_printf (pp, " (depth %i)", range->m_stack_depth);
|
||||
pp_newline (pp);
|
||||
|
||||
/* Print a run of events. */
|
||||
{
|
||||
write_indent (pp, cur_indent + per_frame_indent);
|
||||
pp_string (pp, start_line_color);
|
||||
pp_string (pp, "|");
|
||||
pp_string (pp, end_line_color);
|
||||
pp_newline (pp);
|
||||
if (interprocedural)
|
||||
{
|
||||
write_indent (pp, cur_indent + per_frame_indent);
|
||||
pp_string (pp, start_line_color);
|
||||
pp_string (pp, "|");
|
||||
pp_string (pp, end_line_color);
|
||||
pp_newline (pp);
|
||||
}
|
||||
|
||||
char *saved_prefix = pp_take_prefix (pp);
|
||||
char *prefix;
|
||||
{
|
||||
pretty_printer tmp_pp;
|
||||
write_indent (&tmp_pp, cur_indent + per_frame_indent);
|
||||
pp_string (&tmp_pp, start_line_color);
|
||||
pp_string (&tmp_pp, "|");
|
||||
pp_string (&tmp_pp, end_line_color);
|
||||
prefix = xstrdup (pp_formatted_text (&tmp_pp));
|
||||
}
|
||||
pp_set_prefix (pp, prefix);
|
||||
pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
|
||||
if (interprocedural)
|
||||
{
|
||||
pretty_printer tmp_pp;
|
||||
write_indent (&tmp_pp, cur_indent + per_frame_indent);
|
||||
pp_string (&tmp_pp, start_line_color);
|
||||
pp_string (&tmp_pp, "|");
|
||||
pp_string (&tmp_pp, end_line_color);
|
||||
prefix = xstrdup (pp_formatted_text (&tmp_pp));
|
||||
pp_set_prefix (pp, prefix);
|
||||
pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
|
||||
}
|
||||
range->print (dc);
|
||||
pp_set_prefix (pp, saved_prefix);
|
||||
|
||||
write_indent (pp, cur_indent + per_frame_indent);
|
||||
pp_string (pp, start_line_color);
|
||||
pp_string (pp, "|");
|
||||
pp_string (pp, end_line_color);
|
||||
pp_newline (pp);
|
||||
if (interprocedural)
|
||||
{
|
||||
pp_set_prefix (pp, saved_prefix);
|
||||
write_indent (pp, cur_indent + per_frame_indent);
|
||||
pp_string (pp, start_line_color);
|
||||
pp_string (pp, "|");
|
||||
pp_string (pp, end_line_color);
|
||||
pp_newline (pp);
|
||||
}
|
||||
}
|
||||
|
||||
if (i < m_ranges.length () - 1)
|
||||
if (interprocedural && i < m_ranges.length () - 1)
|
||||
{
|
||||
const path_summary::event_range *next_range
|
||||
= m_ranges[i + 1];
|
||||
@@ -441,51 +464,116 @@ path_summary::print (diagnostic_context *dc, bool show_depths) const
|
||||
}
|
||||
}
|
||||
|
||||
/* Concrete implementation of path_printer.
|
||||
|
||||
Putting this here isolates the path-printing code (which uses tree and
|
||||
thus is in OBJS) from the core diagnostic machinery (which is in
|
||||
OBJS-libcommon). */
|
||||
|
||||
class impl_path_printer : public path_printer
|
||||
{
|
||||
public:
|
||||
bool maybe_print_path_rather_than_richloc (diagnostic_context *context,
|
||||
const rich_location &richloc)
|
||||
FINAL OVERRIDE
|
||||
{
|
||||
switch (context->path_format)
|
||||
{
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
case DPF_NONE:
|
||||
case DPF_SEPARATE_EVENTS:
|
||||
return false;
|
||||
|
||||
case DPF_INLINE_EVENTS:
|
||||
{
|
||||
/* If we can, then print the path here, rather than RICHLOC. */
|
||||
if (richloc.path_makes_location_redundant_p ())
|
||||
{
|
||||
impl_print_path (context, richloc, false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_path (diagnostic_context *context,
|
||||
const rich_location &richloc) FINAL OVERRIDE
|
||||
{
|
||||
switch (context->path_format)
|
||||
{
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
case DPF_NONE:
|
||||
break;
|
||||
case DPF_SEPARATE_EVENTS:
|
||||
{
|
||||
const diagnostic_path *path = richloc.get_path ();
|
||||
gcc_assert (path);
|
||||
|
||||
const unsigned num_events = path->num_events ();
|
||||
|
||||
/* A note per event. */
|
||||
for (unsigned i = 0; i < num_events; i++)
|
||||
{
|
||||
const diagnostic_event &event = path->get_event (i);
|
||||
label_text event_text (event.get_desc (false));
|
||||
gcc_assert (event_text.m_buffer);
|
||||
diagnostic_event_id_t event_id (i);
|
||||
inform (event.get_location (),
|
||||
"%@ %s", &event_id, event_text.m_buffer);
|
||||
event_text.maybe_free ();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DPF_INLINE_EVENTS:
|
||||
{
|
||||
if (richloc.path_makes_location_redundant_p ())
|
||||
{
|
||||
/* Then we already printed the path during diagnostic_show_locus
|
||||
on RICHLOC; nothing left to do. */
|
||||
return;
|
||||
}
|
||||
/* Otherwise, print the path. We have also printed RICHLOC
|
||||
via diagnostic_show_locus, so we must print event headers, to
|
||||
stop the path following on directly from the diagnostic_show_locus
|
||||
call. */
|
||||
impl_print_path (context, richloc, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void impl_print_path (diagnostic_context *context,
|
||||
const rich_location &richloc,
|
||||
bool need_event_header)
|
||||
{
|
||||
const diagnostic_path *path = richloc.get_path ();
|
||||
gcc_assert (path);
|
||||
|
||||
/* Consolidate related events. */
|
||||
path_summary summary (*path, true);
|
||||
char *saved_prefix = pp_take_prefix (context->printer);
|
||||
pp_set_prefix (context->printer, NULL);
|
||||
summary.print (context, context->show_path_depths,
|
||||
need_event_header);
|
||||
pp_flush (context->printer);
|
||||
pp_set_prefix (context->printer, saved_prefix);
|
||||
}
|
||||
};
|
||||
|
||||
} /* end of anonymous namespace for path-printing code. */
|
||||
|
||||
/* Print PATH to CONTEXT, according to CONTEXT's path_format. */
|
||||
/* class path_printer. */
|
||||
|
||||
void
|
||||
default_tree_diagnostic_path_printer (diagnostic_context *context,
|
||||
const diagnostic_path *path)
|
||||
/* Make a concrete path_printer instance.
|
||||
The caller is reponsible for deleting it. */
|
||||
|
||||
path_printer *
|
||||
path_printer::make_tree_default ()
|
||||
{
|
||||
gcc_assert (path);
|
||||
|
||||
const unsigned num_events = path->num_events ();
|
||||
|
||||
switch (context->path_format)
|
||||
{
|
||||
case DPF_NONE:
|
||||
/* Do nothing. */
|
||||
return;
|
||||
|
||||
case DPF_SEPARATE_EVENTS:
|
||||
{
|
||||
/* A note per event. */
|
||||
for (unsigned i = 0; i < num_events; i++)
|
||||
{
|
||||
const diagnostic_event &event = path->get_event (i);
|
||||
label_text event_text (event.get_desc (false));
|
||||
gcc_assert (event_text.m_buffer);
|
||||
diagnostic_event_id_t event_id (i);
|
||||
inform (event.get_location (),
|
||||
"%@ %s", &event_id, event_text.m_buffer);
|
||||
event_text.maybe_free ();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DPF_INLINE_EVENTS:
|
||||
{
|
||||
/* Consolidate related events. */
|
||||
path_summary summary (*path, true);
|
||||
char *saved_prefix = pp_take_prefix (context->printer);
|
||||
pp_set_prefix (context->printer, NULL);
|
||||
summary.print (context, context->show_path_depths);
|
||||
pp_flush (context->printer);
|
||||
pp_set_prefix (context->printer, saved_prefix);
|
||||
}
|
||||
}
|
||||
return new impl_path_printer ();
|
||||
}
|
||||
|
||||
/* This has to be here, rather than diagnostic-format-json.cc,
|
||||
@@ -591,14 +679,21 @@ test_intraprocedural_path (pretty_printer *event_pp)
|
||||
path_summary summary (path, false);
|
||||
ASSERT_EQ (summary.get_num_ranges (), 1);
|
||||
|
||||
test_diagnostic_context dc;
|
||||
summary.print (&dc, true);
|
||||
ASSERT_STREQ (" `foo': events 1-2 (depth 0)\n"
|
||||
" |\n"
|
||||
" | (1): first `free'\n"
|
||||
" | (2): double `free'\n"
|
||||
" |\n",
|
||||
pp_formatted_text (dc.printer));
|
||||
{
|
||||
test_diagnostic_context dc;
|
||||
summary.print (&dc, true, false);
|
||||
ASSERT_STREQ (" (1): first `free'\n"
|
||||
" (2): double `free'\n",
|
||||
pp_formatted_text (dc.printer));
|
||||
}
|
||||
{
|
||||
test_diagnostic_context dc;
|
||||
summary.print (&dc, true, true);
|
||||
ASSERT_STREQ (" events 1-2 (depth 0)\n"
|
||||
" (1): first `free'\n"
|
||||
" (2): double `free'\n",
|
||||
pp_formatted_text (dc.printer));
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify that print_path_summary works on an interprocedural path. */
|
||||
|
||||
@@ -312,6 +312,6 @@ tree_diagnostics_defaults (diagnostic_context *context)
|
||||
diagnostic_starter (context) = default_tree_diagnostic_starter;
|
||||
diagnostic_finalizer (context) = default_diagnostic_finalizer;
|
||||
diagnostic_format_decoder (context) = default_tree_printer;
|
||||
context->print_path = default_tree_diagnostic_path_printer;
|
||||
context->m_path_printer = path_printer::make_tree_default ();
|
||||
context->make_json_for_path = default_tree_make_json_for_path;
|
||||
}
|
||||
|
||||
@@ -57,8 +57,6 @@ void tree_diagnostics_defaults (diagnostic_context *context);
|
||||
bool default_tree_printer (pretty_printer *, text_info *, const char *,
|
||||
int, bool, bool, bool, bool *, const char **);
|
||||
|
||||
extern void default_tree_diagnostic_path_printer (diagnostic_context *,
|
||||
const diagnostic_path *);
|
||||
extern json::value *default_tree_make_json_for_path (diagnostic_context *,
|
||||
const diagnostic_path *);
|
||||
|
||||
|
||||
@@ -1732,6 +1732,8 @@ class rich_location
|
||||
const diagnostic_path *get_path () const { return m_path; }
|
||||
void set_path (const diagnostic_path *path) { m_path = path; }
|
||||
|
||||
bool path_makes_location_redundant_p () const;
|
||||
|
||||
private:
|
||||
bool reject_impossible_fixit (location_t where);
|
||||
void stop_supporting_fixits ();
|
||||
|
||||
Reference in New Issue
Block a user