Skip to content

Commit

Permalink
diagnostics, analyzer: add optional per-diagnostic property bags to S…
Browse files Browse the repository at this point in the history
…ARIF

I've found it useful in debugging the analyzer for the SARIF output to
contain extra analyzer-specific data in each diagnostic.

This patch:
* adds a way for a diagnostic_metadata to populate a property
bag within a SARIF "result" object based on a new vfunc
* reworks how diagnostics are emitted within the analyzer so
that a custom diagnostic_metadata subclass is used, which populates
the property bag with information from the saved_diagnostic, and with
a vfunc hook allowing for per-pending_diagnotic-subclass extra
properties.

Doing so makes it trivial to go from the SARIF output back to
pertinent parts of the analyzer's internals (e.g. the index of
the diagnostic within the ana::diagnostic_manager, the index of
the ana::exploded_node, etc).

It also replaces a lot of boilerplate in the "emit" implementations
in the various pending_diagnostics subclasses.  In particular, doing
so fixes missing CVE metadata for -Wanalyzer-fd-phase-mismatch (where
sm-fd.cc's fd_phase_mismatch::emit was failing to use its
diagnostic_metadata instance).

gcc/analyzer/ChangeLog:
	* analyzer.h (class saved_diagnostic): New forward decl.
	* bounds-checking.cc: Update for changes to
	pending_diagnostic::emit.
	* call-details.cc: Likewise.
	* diagnostic-manager.cc: Include "diagnostic-format-sarif.h".
	(saved_diagnostic::maybe_add_sarif_properties): New.
	(class pending_diagnostic_metadata): New.
	(diagnostic_manager::emit_saved_diagnostic): Create a
	pending_diagnostic_metadata and a diagnostic_emission_context.
	Pass the latter to the pending_diagnostic::emit vfunc.
	* diagnostic-manager.h
	(saved_diagnostic::maybe_add_sarif_properties): New decl.
	* engine.cc: Update for changes to pending_diagnostic::emit.
	* infinite-loop.cc: Likewise.
	* infinite-recursion.cc: Likewise.
	* kf-analyzer.cc: Likewise.
	* kf.cc: Likewise.
	* pending-diagnostic.cc
	(diagnostic_emission_context::get_pending_diagnostic): New.
	(diagnostic_emission_context::warn): New.
	(diagnostic_emission_context::inform): New.
	* pending-diagnostic.h (class diagnostic_emission_context): New.
	(pending_diagnostic::emit): Update params.
	(pending_diagnostic::maybe_add_sarif_properties): New vfunc.
	* region.cc: Don't include "diagnostic-metadata.h".
	* region-model.cc: Include "diagnostic-format-sarif.h".  Update
	for changes to pending_diagnostic::emit.
	(exposure_through_uninit_copy::maybe_add_sarif_properties): New.
	* sm-fd.cc: Update for changes to pending_diagnostic::emit.
	* sm-file.cc: Likewise.
	* sm-malloc.cc: Likewise.
	* sm-pattern-test.cc: Likewise.
	* sm-sensitive.cc: Likewise.
	* sm-signal.cc: Likewise.
	* sm-taint.cc: Likewise.
	* store.cc: Don't include "diagnostic-metadata.h".
	* varargs.cc: Update for changes to pending_diagnostic::emit.

gcc/ChangeLog:
	* diagnostic-core.h (emit_diagnostic_valist): New overload decl.
	* diagnostic-format-sarif.cc (sarif_builder::make_result_object):
	When we have metadata, call its maybe_add_sarif_properties vfunc.
	* diagnostic-metadata.h (class sarif_object): Forward decl.
	(diagnostic_metadata::~diagnostic_metadata): New.
	(diagnostic_metadata::maybe_add_sarif_properties): New vfunc.
	* diagnostic.cc (emit_diagnostic_valist): New overload.

gcc/testsuite/ChangeLog:
	* gcc.dg/analyzer/fd-accept.c: Update for fix to missing CWE
	metadata for -Wanalyzer-fd-phase-mismatch.
	* gcc.dg/analyzer/fd-bind.c: Likewise.
	* gcc.dg/analyzer/fd-socket-misuse.c: Likewise.
	* gcc.dg/plugin/analyzer_cpython_plugin.c: Update for changes to
	pending_diagnostic::emit.
	* gcc.dg/plugin/analyzer_gil_plugin.c: Likewise.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
  • Loading branch information
davidmalcolm committed Dec 1, 2023
1 parent 83b210d commit 12b67d1
Show file tree
Hide file tree
Showing 32 changed files with 550 additions and 533 deletions.
1 change: 1 addition & 0 deletions gcc/analyzer/analyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class bounded_ranges_manager;
struct pending_location;
class pending_diagnostic;
class pending_note;
class saved_diagnostic;
struct event_loc_info;
class checker_event;
class state_change_event;
Expand Down
130 changes: 52 additions & 78 deletions gcc/analyzer/bounds-checking.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ along with GCC; see the file COPYING3. If not see
#include "gimple.h"
#include "gimple-iterator.h"
#include "diagnostic-core.h"
#include "diagnostic-metadata.h"
#include "diagnostic-diagram.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
Expand Down Expand Up @@ -119,10 +118,10 @@ class out_of_bounds : public pending_diagnostic
}

void
maybe_show_notes (location_t loc, logger *logger) const
maybe_show_notes (diagnostic_emission_context &ctxt) const
{
maybe_describe_array_bounds (loc);
maybe_show_diagram (logger);
maybe_describe_array_bounds (ctxt.get_location ());
maybe_show_diagram (ctxt.get_logger ());
}

/* Potentially add a note about valid ways to index this array, such
Expand Down Expand Up @@ -281,27 +280,22 @@ class concrete_buffer_overflow : public concrete_past_the_end
return "concrete_buffer_overflow";
}

bool emit (rich_location *rich_loc,
logger *logger) final override
bool emit (diagnostic_emission_context &ctxt) final override
{
diagnostic_metadata m;
bool warned;
switch (get_memory_space ())
{
default:
m.add_cwe (787);
warned = warning_meta (rich_loc, m, get_controlling_option (),
"buffer overflow");
ctxt.add_cwe (787);
warned = ctxt.warn ("buffer overflow");
break;
case MEMSPACE_STACK:
m.add_cwe (121);
warned = warning_meta (rich_loc, m, get_controlling_option (),
"stack-based buffer overflow");
ctxt.add_cwe (121);
warned = ctxt.warn ("stack-based buffer overflow");
break;
case MEMSPACE_HEAP:
m.add_cwe (122);
warned = warning_meta (rich_loc, m, get_controlling_option (),
"heap-based buffer overflow");
ctxt.add_cwe (122);
warned = ctxt.warn ("heap-based buffer overflow");
break;
}

Expand All @@ -312,25 +306,25 @@ class concrete_buffer_overflow : public concrete_past_the_end
unsigned HOST_WIDE_INT num_bad_bytes
= m_out_of_bounds_range.m_size_in_bytes.to_uhwi ();
if (m_diag_arg)
inform_n (rich_loc->get_loc (),
inform_n (ctxt.get_location (),
num_bad_bytes,
"write of %wu byte to beyond the end of %qE",
"write of %wu bytes to beyond the end of %qE",
num_bad_bytes,
m_diag_arg);
else
inform_n (rich_loc->get_loc (),
inform_n (ctxt.get_location (),
num_bad_bytes,
"write of %wu byte to beyond the end of the region",
"write of %wu bytes to beyond the end of the region",
num_bad_bytes);
}
else if (m_diag_arg)
inform (rich_loc->get_loc (),
inform (ctxt.get_location (),
"write to beyond the end of %qE",
m_diag_arg);

maybe_show_notes (rich_loc->get_loc (), logger);
maybe_show_notes (ctxt);
}

return warned;
Expand Down Expand Up @@ -388,24 +382,20 @@ class concrete_buffer_over_read : public concrete_past_the_end
return "concrete_buffer_over_read";
}

bool emit (rich_location *rich_loc, logger *logger) final override
bool emit (diagnostic_emission_context &ctxt) final override
{
diagnostic_metadata m;
bool warned;
m.add_cwe (126);
ctxt.add_cwe (126);
switch (get_memory_space ())
{
default:
warned = warning_meta (rich_loc, m, get_controlling_option (),
"buffer over-read");
warned = ctxt.warn ("buffer over-read");
break;
case MEMSPACE_STACK:
warned = warning_meta (rich_loc, m, get_controlling_option (),
"stack-based buffer over-read");
warned = ctxt.warn ("stack-based buffer over-read");
break;
case MEMSPACE_HEAP:
warned = warning_meta (rich_loc, m, get_controlling_option (),
"heap-based buffer over-read");
warned = ctxt.warn ("heap-based buffer over-read");
break;
}

Expand All @@ -416,25 +406,25 @@ class concrete_buffer_over_read : public concrete_past_the_end
unsigned HOST_WIDE_INT num_bad_bytes
= m_out_of_bounds_range.m_size_in_bytes.to_uhwi ();
if (m_diag_arg)
inform_n (rich_loc->get_loc (),
inform_n (ctxt.get_location (),
num_bad_bytes,
"read of %wu byte from after the end of %qE",
"read of %wu bytes from after the end of %qE",
num_bad_bytes,
m_diag_arg);
else
inform_n (rich_loc->get_loc (),
inform_n (ctxt.get_location (),
num_bad_bytes,
"read of %wu byte from after the end of the region",
"read of %wu bytes from after the end of the region",
num_bad_bytes);
}
else if (m_diag_arg)
inform (rich_loc->get_loc (),
inform (ctxt.get_location (),
"read from after the end of %qE",
m_diag_arg);

maybe_show_notes (rich_loc->get_loc (), logger);
maybe_show_notes (ctxt);
}

return warned;
Expand Down Expand Up @@ -493,28 +483,24 @@ class concrete_buffer_underwrite : public concrete_out_of_bounds
return "concrete_buffer_underwrite";
}

bool emit (rich_location *rich_loc, logger *logger) final override
bool emit (diagnostic_emission_context &ctxt) final override
{
diagnostic_metadata m;
bool warned;
m.add_cwe (124);
ctxt.add_cwe (124);
switch (get_memory_space ())
{
default:
warned = warning_meta (rich_loc, m, get_controlling_option (),
"buffer underwrite");
warned = ctxt.warn ("buffer underwrite");
break;
case MEMSPACE_STACK:
warned = warning_meta (rich_loc, m, get_controlling_option (),
"stack-based buffer underwrite");
warned = ctxt.warn ("stack-based buffer underwrite");
break;
case MEMSPACE_HEAP:
warned = warning_meta (rich_loc, m, get_controlling_option (),
"heap-based buffer underwrite");
warned = ctxt.warn ("heap-based buffer underwrite");
break;
}
if (warned)
maybe_show_notes (rich_loc->get_loc (), logger);
maybe_show_notes (ctxt);
return warned;
}

Expand Down Expand Up @@ -568,28 +554,24 @@ class concrete_buffer_under_read : public concrete_out_of_bounds
return "concrete_buffer_under_read";
}

bool emit (rich_location *rich_loc, logger *logger) final override
bool emit (diagnostic_emission_context &ctxt) final override
{
diagnostic_metadata m;
bool warned;
m.add_cwe (127);
ctxt.add_cwe (127);
switch (get_memory_space ())
{
default:
warned = warning_meta (rich_loc, m, get_controlling_option (),
"buffer under-read");
warned = ctxt.warn ("buffer under-read");
break;
case MEMSPACE_STACK:
warned = warning_meta (rich_loc, m, get_controlling_option (),
"stack-based buffer under-read");
warned = ctxt.warn ("stack-based buffer under-read");
break;
case MEMSPACE_HEAP:
warned = warning_meta (rich_loc, m, get_controlling_option (),
"heap-based buffer under-read");
warned = ctxt.warn ("heap-based buffer under-read");
break;
}
if (warned)
maybe_show_notes (rich_loc->get_loc (), logger);
maybe_show_notes (ctxt);
return warned;
}

Expand Down Expand Up @@ -679,30 +661,26 @@ class symbolic_buffer_overflow : public symbolic_past_the_end
return "symbolic_buffer_overflow";
}

bool emit (rich_location *rich_loc, logger *logger) final override
bool emit (diagnostic_emission_context &ctxt) final override
{
diagnostic_metadata m;
bool warned;
switch (get_memory_space ())
{
default:
m.add_cwe (787);
warned = warning_meta (rich_loc, m, get_controlling_option (),
"buffer overflow");
ctxt.add_cwe (787);
warned = ctxt.warn ("buffer overflow");
break;
case MEMSPACE_STACK:
m.add_cwe (121);
warned = warning_meta (rich_loc, m, get_controlling_option (),
"stack-based buffer overflow");
ctxt.add_cwe (121);
warned = ctxt.warn ("stack-based buffer overflow");
break;
case MEMSPACE_HEAP:
m.add_cwe (122);
warned = warning_meta (rich_loc, m, get_controlling_option (),
"heap-based buffer overflow");
ctxt.add_cwe (122);
warned = ctxt.warn ("heap-based buffer overflow");
break;
}
if (warned)
maybe_show_notes (rich_loc->get_loc (), logger);
maybe_show_notes (ctxt);
return warned;
}

Expand Down Expand Up @@ -796,31 +774,27 @@ class symbolic_buffer_over_read : public symbolic_past_the_end
return "symbolic_buffer_over_read";
}

bool emit (rich_location *rich_loc, logger *logger) final override
bool emit (diagnostic_emission_context &ctxt) final override
{
diagnostic_metadata m;
m.add_cwe (126);
ctxt.add_cwe (126);
bool warned;
switch (get_memory_space ())
{
default:
m.add_cwe (787);
warned = warning_meta (rich_loc, m, get_controlling_option (),
"buffer over-read");
ctxt.add_cwe (787);
warned = ctxt.warn ("buffer over-read");
break;
case MEMSPACE_STACK:
m.add_cwe (121);
warned = warning_meta (rich_loc, m, get_controlling_option (),
"stack-based buffer over-read");
ctxt.add_cwe (121);
warned = ctxt.warn ("stack-based buffer over-read");
break;
case MEMSPACE_HEAP:
m.add_cwe (122);
warned = warning_meta (rich_loc, m, get_controlling_option (),
"heap-based buffer over-read");
ctxt.add_cwe (122);
warned = ctxt.warn ("heap-based buffer over-read");
break;
}
if (warned)
maybe_show_notes (rich_loc->get_loc (), logger);
maybe_show_notes (ctxt);
return warned;
}

Expand Down
8 changes: 3 additions & 5 deletions gcc/analyzer/call-details.cc
Original file line number Diff line number Diff line change
Expand Up @@ -445,14 +445,12 @@ class overlapping_buffers
return OPT_Wanalyzer_overlapping_buffers;
}

bool emit (rich_location *rich_loc, logger *) final override
bool emit (diagnostic_emission_context &ctxt) final override
{
auto_diagnostic_group d;

bool warned;
warned = warning_at (rich_loc, get_controlling_option (),
"overlapping buffers passed as arguments to %qD",
m_fndecl);
bool warned = ctxt.warn ("overlapping buffers passed as arguments to %qD",
m_fndecl);

// TODO: draw a picture?

Expand Down

0 comments on commit 12b67d1

Please sign in to comment.