Add diagnostic_metadata and CWE support

This patch adds support for associating a diagnostic message with an
optional diagnostic_metadata object, so that plugins can add extra data
to their diagnostics (e.g. mapping a diagnostic to a taxonomy or coding
standard such as from CERT or MISRA).

Currently this only supports associating a CWE identifier with a
diagnostic (which is what I'm using for the warnings in the analyzer
patch kit), but adding a diagnostic_metadata class allows for future
growth in this area without an explosion of further "warning_at"
overloads for all of the different kinds of custom data that a plugin
might want to add.

This version of the patch renames the overly-general
-fdiagnostics-show-metadata to -fdiagnostics-show-cwe and adds test
coverage for it via a plugin.

It also adds a note to the documentation that no GCC diagnostics
currently use this; it's a feature for plugins (and, at some point,
I hope, the analyzer).

gcc/ChangeLog:
	* common.opt (fdiagnostics-show-cwe): Add.
	* diagnostic-core.h (class diagnostic_metadata): New forward decl.
	(warning_at): Add overload taking a const diagnostic_metadata &.
	(emit_diagnostic_valist): Add overload taking a
	const diagnostic_metadata *.
	* diagnostic-format-json.cc: Include "diagnostic-metadata.h".
	(json_from_metadata): New function.
	(json_end_diagnostic): Call it to add "metadata" child for
	diagnostics with metadata.
	(diagnostic_output_format_init): Clear context->show_cwe.
	* diagnostic-metadata.h: New file.
	* diagnostic.c: Include "diagnostic-metadata.h".
	(diagnostic_impl): Add const diagnostic_metadata * param.
	(diagnostic_n_impl): Likewise.
	(diagnostic_initialize): Initialize context->show_cwe.
	(diagnostic_set_info_translated): Initialize diagnostic->metadata.
	(get_cwe_url): New function.
	(print_any_cwe): New function.
	(diagnostic_report_diagnostic): Call print_any_cwe if the
	diagnostic has non-NULL metadata.
	(emit_diagnostic): Pass NULL as the metadata in the call to
	diagnostic_impl.
	(emit_diagnostic_valist): Likewise.
	(emit_diagnostic_valist): New overload taking a
	const diagnostic_metadata *.
	(inform): Pass NULL as the metadata in the call to
	diagnostic_impl.
	(inform_n): Likewise for diagnostic_n_impl.
	(warning): Likewise.
	(warning_at): Likewise.  Add overload that takes a
	const diagnostic_metadata &.
	(warning_n): Pass NULL as the metadata in the call to
	diagnostic_n_impl.
	(pedwarn): Likewise for diagnostic_impl.
	(permerror): Likewise.
	(error): Likewise.
	(error_n): Likewise.
	(error_at): Likewise.
	(sorry): Likewise.
	(sorry_at): Likewise.
	(fatal_error): Likewise.
	(internal_error): Likewise.
	(internal_error_no_backtrace): Likewise.
	* diagnostic.h (diagnostic_info::metadata): New field.
	(diagnostic_context::show_cwe): New field.
	* doc/invoke.texi (-fno-diagnostics-show-cwe): New option.
	* opts.c (common_handle_option): Handle OPT_fdiagnostics_show_cwe.
	* toplev.c (general_init): Initialize global_dc->show_cwe.

gcc/testsuite/ChangeLog:
	* gcc.dg/plugin/diagnostic-test-metadata.c: New test.
	* gcc.dg/plugin/diagnostic_plugin_test_metadata.c: New test plugin.
	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add them.

From-SVN: r279556
This commit is contained in:
David Malcolm 2019-12-18 23:58:49 +00:00 committed by David Malcolm
parent a7a09efa24
commit 6d4a35ca57
14 changed files with 422 additions and 31 deletions

View File

@ -1,3 +1,54 @@
2019-12-18 David Malcolm <dmalcolm@redhat.com>
* common.opt (fdiagnostics-show-cwe): Add.
* diagnostic-core.h (class diagnostic_metadata): New forward decl.
(warning_at): Add overload taking a const diagnostic_metadata &.
(emit_diagnostic_valist): Add overload taking a
const diagnostic_metadata *.
* diagnostic-format-json.cc: Include "diagnostic-metadata.h".
(json_from_metadata): New function.
(json_end_diagnostic): Call it to add "metadata" child for
diagnostics with metadata.
(diagnostic_output_format_init): Clear context->show_cwe.
* diagnostic-metadata.h: New file.
* diagnostic.c: Include "diagnostic-metadata.h".
(diagnostic_impl): Add const diagnostic_metadata * param.
(diagnostic_n_impl): Likewise.
(diagnostic_initialize): Initialize context->show_cwe.
(diagnostic_set_info_translated): Initialize diagnostic->metadata.
(get_cwe_url): New function.
(print_any_cwe): New function.
(diagnostic_report_diagnostic): Call print_any_cwe if the
diagnostic has non-NULL metadata.
(emit_diagnostic): Pass NULL as the metadata in the call to
diagnostic_impl.
(emit_diagnostic_valist): Likewise.
(emit_diagnostic_valist): New overload taking a
const diagnostic_metadata *.
(inform): Pass NULL as the metadata in the call to
diagnostic_impl.
(inform_n): Likewise for diagnostic_n_impl.
(warning): Likewise.
(warning_at): Likewise. Add overload that takes a
const diagnostic_metadata &.
(warning_n): Pass NULL as the metadata in the call to
diagnostic_n_impl.
(pedwarn): Likewise for diagnostic_impl.
(permerror): Likewise.
(error): Likewise.
(error_n): Likewise.
(error_at): Likewise.
(sorry): Likewise.
(sorry_at): Likewise.
(fatal_error): Likewise.
(internal_error): Likewise.
(internal_error_no_backtrace): Likewise.
* diagnostic.h (diagnostic_info::metadata): New field.
(diagnostic_context::show_cwe): New field.
* doc/invoke.texi (-fno-diagnostics-show-cwe): New option.
* opts.c (common_handle_option): Handle OPT_fdiagnostics_show_cwe.
* toplev.c (general_init): Initialize global_dc->show_cwe.
2019-12-19 Julian Brown <julian@codesourcery.com>
Maciej W. Rozycki <macro@codesourcery.com>
Tobias Burnus <tobias@codesourcery.com>

View File

@ -1334,6 +1334,10 @@ fdiagnostics-show-option
Common Var(flag_diagnostics_show_option) Init(1)
Amend appropriate diagnostic messages with the command line option that controls them.
fdiagnostics-show-cwe
Common Var(flag_diagnostics_show_cwe) Init(1)
Print CWE identifiers for diagnostic messages, where available.
fdiagnostics-minimum-margin-width=
Common Joined UInteger Var(diagnostics_minimum_margin_width) Init(6)
Set minimum width of left margin of source code when showing source.

View File

@ -45,6 +45,9 @@ class auto_diagnostic_group
~auto_diagnostic_group ();
};
/* Forward decl. */
class diagnostic_metadata; /* See diagnostic-metadata.h. */
extern const char *progname;
extern const char *trim_filename (const char *);
@ -78,6 +81,9 @@ extern bool warning_at (location_t, int, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern bool warning_at (rich_location *, int, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern bool warning_at (rich_location *, const diagnostic_metadata &, int,
const char *, ...)
ATTRIBUTE_GCC_DIAG(4,5);
extern void error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
extern void error_n (location_t, unsigned HOST_WIDE_INT, const char *,
const char *, ...)
@ -109,6 +115,10 @@ extern bool emit_diagnostic (diagnostic_t, rich_location *, int,
const char *, ...) ATTRIBUTE_GCC_DIAG(4,5);
extern bool emit_diagnostic_valist (diagnostic_t, location_t, int, const char *,
va_list *) ATTRIBUTE_GCC_DIAG (4,0);
extern bool emit_diagnostic_valist (diagnostic_t, rich_location *,
const diagnostic_metadata *metadata,
int, const char *, va_list *)
ATTRIBUTE_GCC_DIAG (5,0);
extern bool seen_error (void);
#ifdef BUFSIZ

View File

@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
#include "diagnostic-metadata.h"
#include "json.h"
#include "selftest.h"
@ -103,6 +104,20 @@ json_from_fixit_hint (const fixit_hint *hint)
return fixit_obj;
}
/* Generate a JSON object for METADATA. */
static json::object *
json_from_metadata (const diagnostic_metadata *metadata)
{
json::object *metadata_obj = new json::object ();
if (metadata->get_cwe ())
metadata_obj->set ("cwe",
new json::integer_number (metadata->get_cwe ()));
return metadata_obj;
}
/* No-op implementation of "begin_diagnostic" for JSON output. */
static void
@ -211,6 +226,12 @@ json_end_diagnostic (diagnostic_context *context, diagnostic_info *diagnostic,
TODO: functions
TODO: inlining information
TODO: macro expansion information. */
if (diagnostic->metadata)
{
json::object *metadata_obj = json_from_metadata (diagnostic->metadata);
diag_obj->set ("metadata", metadata_obj);
}
}
/* No-op implementation of "begin_group_cb" for JSON output. */
@ -268,6 +289,9 @@ diagnostic_output_format_init (diagnostic_context *context,
context->end_group_cb = json_end_group;
context->final_cb = json_final_cb;
/* The metadata is handled in JSON format, rather than as text. */
context->show_cwe = false;
/* The option is handled in JSON format, rather than as text. */
context->show_option_requested = false;

42
gcc/diagnostic-metadata.h Normal file
View File

@ -0,0 +1,42 @@
/* Additional metadata for a diagnostic.
Copyright (C) 2019 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_DIAGNOSTIC_METADATA_H
#define GCC_DIAGNOSTIC_METADATA_H
/* A bundle of additional metadata that can be associated with a
diagnostic.
Currently this only supports associating a CWE identifier with a
diagnostic. */
class diagnostic_metadata
{
public:
diagnostic_metadata () : m_cwe (0) {}
void add_cwe (int cwe) { m_cwe = cwe; }
int get_cwe () const { return m_cwe; }
private:
int m_cwe;
};
#endif /* ! GCC_DIAGNOSTIC_METADATA_H */

View File

@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h"
#include "diagnostic-color.h"
#include "diagnostic-url.h"
#include "diagnostic-metadata.h"
#include "edit-context.h"
#include "selftest.h"
#include "selftest-diagnostic.h"
@ -58,11 +59,13 @@ along with GCC; see the file COPYING3. If not see
#define permissive_error_option(DC) ((DC)->opt_permissive)
/* Prototypes. */
static bool diagnostic_impl (rich_location *, int, const char *,
va_list *, diagnostic_t) ATTRIBUTE_GCC_DIAG(3,0);
static bool diagnostic_n_impl (rich_location *, int, unsigned HOST_WIDE_INT,
static bool diagnostic_impl (rich_location *, const diagnostic_metadata *,
int, const char *,
va_list *, diagnostic_t) ATTRIBUTE_GCC_DIAG(4,0);
static bool diagnostic_n_impl (rich_location *, const diagnostic_metadata *,
int, unsigned HOST_WIDE_INT,
const char *, const char *, va_list *,
diagnostic_t) ATTRIBUTE_GCC_DIAG(5,0);
diagnostic_t) ATTRIBUTE_GCC_DIAG(6,0);
static void error_recursion (diagnostic_context *) ATTRIBUTE_NORETURN;
static void real_abort (void) ATTRIBUTE_NORETURN;
@ -183,6 +186,7 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
diagnostic_set_caret_max_width (context, pp_line_cutoff (context->printer));
for (i = 0; i < rich_location::STATICALLY_ALLOCATED_RANGES; i++)
context->caret_chars[i] = '^';
context->show_cwe = false;
context->show_option_requested = false;
context->abort_on_error = false;
context->show_column = false;
@ -299,6 +303,7 @@ diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
diagnostic->message.format_spec = msg;
diagnostic->message.m_richloc = richloc;
diagnostic->richloc = richloc;
diagnostic->metadata = NULL;
diagnostic->kind = kind;
diagnostic->option_index = 0;
}
@ -898,6 +903,47 @@ update_effective_level_from_pragmas (diagnostic_context *context,
return diag_class;
}
/* Generate a URL string describing CWE. The caller is responsible for
freeing the string. */
static char *
get_cwe_url (int cwe)
{
return xasprintf ("https://cwe.mitre.org/data/definitions/%i.html", cwe);
}
/* If DIAGNOSTIC has a CWE identifier, print it.
For example, if the diagnostic metadata associates it with CWE-119,
" [CWE-119]" will be printed, suitably colorized, and with a URL of a
description of the security issue. */
static void
print_any_cwe (diagnostic_context *context,
const diagnostic_info *diagnostic)
{
if (diagnostic->metadata == NULL)
return;
int cwe = diagnostic->metadata->get_cwe ();
if (cwe)
{
pretty_printer *pp = context->printer;
char *saved_prefix = pp_take_prefix (context->printer);
pp_string (pp, " [");
pp_string (pp, colorize_start (pp_show_color (pp),
diagnostic_kind_color[diagnostic->kind]));
char *cwe_url = get_cwe_url (cwe);
pp_begin_url (pp, cwe_url);
free (cwe_url);
pp_printf (pp, "CWE-%i", cwe);
pp_set_prefix (context->printer, saved_prefix);
pp_end_url (pp);
pp_string (pp, colorize_stop (pp_show_color (pp)));
pp_character (pp, ']');
}
}
/* Print any metadata about the option used to control DIAGNOSTIC to CONTEXT's
printer, e.g. " [-Werror=uninitialized]".
Subroutine of diagnostic_report_diagnostic. */
@ -1058,6 +1104,8 @@ diagnostic_report_diagnostic (diagnostic_context *context,
pp_format (context->printer, &diagnostic->message);
(*diagnostic_starter (context)) (context, diagnostic);
pp_output_formatted_text (context->printer);
if (context->show_cwe)
print_any_cwe (context, diagnostic);
if (context->show_option_requested)
print_option_information (context, diagnostic, orig_diag_kind);
(*diagnostic_finalizer (context)) (context, diagnostic, orig_diag_kind);
@ -1183,8 +1231,8 @@ diagnostic_append_note (diagnostic_context *context,
permerror, error, error_at, error_at, sorry, fatal_error, internal_error,
and internal_error_no_backtrace, as documented and defined below. */
static bool
diagnostic_impl (rich_location *richloc, int opt,
const char *gmsgid,
diagnostic_impl (rich_location *richloc, const diagnostic_metadata *metadata,
int opt, const char *gmsgid,
va_list *ap, diagnostic_t kind)
{
diagnostic_info diagnostic;
@ -1200,13 +1248,15 @@ diagnostic_impl (rich_location *richloc, int opt,
if (kind == DK_WARNING || kind == DK_PEDWARN)
diagnostic.option_index = opt;
}
diagnostic.metadata = metadata;
return diagnostic_report_diagnostic (global_dc, &diagnostic);
}
/* Implement inform_n, warning_n, and error_n, as documented and
defined below. */
static bool
diagnostic_n_impl (rich_location *richloc, int opt, unsigned HOST_WIDE_INT n,
diagnostic_n_impl (rich_location *richloc, const diagnostic_metadata *metadata,
int opt, unsigned HOST_WIDE_INT n,
const char *singular_gmsgid,
const char *plural_gmsgid,
va_list *ap, diagnostic_t kind)
@ -1226,6 +1276,7 @@ diagnostic_n_impl (rich_location *richloc, int opt, unsigned HOST_WIDE_INT n,
diagnostic_set_info_translated (&diagnostic, text, ap, richloc, kind);
if (kind == DK_WARNING)
diagnostic.option_index = opt;
diagnostic.metadata = metadata;
return diagnostic_report_diagnostic (global_dc, &diagnostic);
}
@ -1239,7 +1290,7 @@ emit_diagnostic (diagnostic_t kind, location_t location, int opt,
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, location);
bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap, kind);
bool ret = diagnostic_impl (&richloc, NULL, opt, gmsgid, &ap, kind);
va_end (ap);
return ret;
}
@ -1253,7 +1304,7 @@ emit_diagnostic (diagnostic_t kind, rich_location *richloc, int opt,
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, kind);
bool ret = diagnostic_impl (richloc, NULL, opt, gmsgid, &ap, kind);
va_end (ap);
return ret;
}
@ -1265,7 +1316,18 @@ emit_diagnostic_valist (diagnostic_t kind, location_t location, int opt,
const char *gmsgid, va_list *ap)
{
rich_location richloc (line_table, location);
return diagnostic_impl (&richloc, opt, gmsgid, ap, kind);
return diagnostic_impl (&richloc, NULL, opt, gmsgid, ap, kind);
}
/* Wrapper around diagnostic_impl taking a va_list parameter. */
bool
emit_diagnostic_valist (diagnostic_t kind, rich_location *richloc,
const diagnostic_metadata *metadata,
int opt,
const char *gmsgid, va_list *ap)
{
return diagnostic_impl (richloc, metadata, opt, gmsgid, ap, kind);
}
/* An informative note at LOCATION. Use this for additional details on an error
@ -1277,7 +1339,7 @@ inform (location_t location, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, location);
diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_NOTE);
diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_NOTE);
va_end (ap);
}
@ -1290,7 +1352,7 @@ inform (rich_location *richloc, const char *gmsgid, ...)
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
diagnostic_impl (richloc, -1, gmsgid, &ap, DK_NOTE);
diagnostic_impl (richloc, NULL, -1, gmsgid, &ap, DK_NOTE);
va_end (ap);
}
@ -1304,7 +1366,7 @@ inform_n (location_t location, unsigned HOST_WIDE_INT n,
va_start (ap, plural_gmsgid);
auto_diagnostic_group d;
rich_location richloc (line_table, location);
diagnostic_n_impl (&richloc, -1, n, singular_gmsgid, plural_gmsgid,
diagnostic_n_impl (&richloc, NULL, -1, n, singular_gmsgid, plural_gmsgid,
&ap, DK_NOTE);
va_end (ap);
}
@ -1319,7 +1381,7 @@ warning (int opt, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, input_location);
bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap, DK_WARNING);
bool ret = diagnostic_impl (&richloc, NULL, opt, gmsgid, &ap, DK_WARNING);
va_end (ap);
return ret;
}
@ -1335,7 +1397,7 @@ warning_at (location_t location, int opt, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, location);
bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap, DK_WARNING);
bool ret = diagnostic_impl (&richloc, NULL, opt, gmsgid, &ap, DK_WARNING);
va_end (ap);
return ret;
}
@ -1350,7 +1412,25 @@ warning_at (rich_location *richloc, int opt, const char *gmsgid, ...)
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, DK_WARNING);
bool ret = diagnostic_impl (richloc, NULL, opt, gmsgid, &ap, DK_WARNING);
va_end (ap);
return ret;
}
/* Same as "warning at" above, but using METADATA. */
bool
warning_at (rich_location *richloc, const diagnostic_metadata &metadata,
int opt, const char *gmsgid, ...)
{
gcc_assert (richloc);
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
bool ret
= diagnostic_impl (richloc, &metadata, opt, gmsgid, &ap,
DK_WARNING);
va_end (ap);
return ret;
}
@ -1366,7 +1446,7 @@ warning_n (rich_location *richloc, int opt, unsigned HOST_WIDE_INT n,
auto_diagnostic_group d;
va_list ap;
va_start (ap, plural_gmsgid);
bool ret = diagnostic_n_impl (richloc, opt, n,
bool ret = diagnostic_n_impl (richloc, NULL, opt, n,
singular_gmsgid, plural_gmsgid,
&ap, DK_WARNING);
va_end (ap);
@ -1385,7 +1465,7 @@ warning_n (location_t location, int opt, unsigned HOST_WIDE_INT n,
va_list ap;
va_start (ap, plural_gmsgid);
rich_location richloc (line_table, location);
bool ret = diagnostic_n_impl (&richloc, opt, n,
bool ret = diagnostic_n_impl (&richloc, NULL, opt, n,
singular_gmsgid, plural_gmsgid,
&ap, DK_WARNING);
va_end (ap);
@ -1412,7 +1492,7 @@ pedwarn (location_t location, int opt, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, location);
bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap, DK_PEDWARN);
bool ret = diagnostic_impl (&richloc, NULL, opt, gmsgid, &ap, DK_PEDWARN);
va_end (ap);
return ret;
}
@ -1427,7 +1507,7 @@ pedwarn (rich_location *richloc, int opt, const char *gmsgid, ...)
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, DK_PEDWARN);
bool ret = diagnostic_impl (richloc, NULL, opt, gmsgid, &ap, DK_PEDWARN);
va_end (ap);
return ret;
}
@ -1446,7 +1526,7 @@ permerror (location_t location, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, location);
bool ret = diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_PERMERROR);
bool ret = diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_PERMERROR);
va_end (ap);
return ret;
}
@ -1461,7 +1541,7 @@ permerror (rich_location *richloc, const char *gmsgid, ...)
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
bool ret = diagnostic_impl (richloc, -1, gmsgid, &ap, DK_PERMERROR);
bool ret = diagnostic_impl (richloc, NULL, -1, gmsgid, &ap, DK_PERMERROR);
va_end (ap);
return ret;
}
@ -1475,7 +1555,7 @@ error (const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, input_location);
diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ERROR);
diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_ERROR);
va_end (ap);
}
@ -1489,7 +1569,7 @@ error_n (location_t location, unsigned HOST_WIDE_INT n,
va_list ap;
va_start (ap, plural_gmsgid);
rich_location richloc (line_table, location);
diagnostic_n_impl (&richloc, -1, n, singular_gmsgid, plural_gmsgid,
diagnostic_n_impl (&richloc, NULL, -1, n, singular_gmsgid, plural_gmsgid,
&ap, DK_ERROR);
va_end (ap);
}
@ -1502,7 +1582,7 @@ error_at (location_t loc, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, loc);
diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ERROR);
diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_ERROR);
va_end (ap);
}
@ -1516,7 +1596,7 @@ error_at (rich_location *richloc, const char *gmsgid, ...)
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
diagnostic_impl (richloc, -1, gmsgid, &ap, DK_ERROR);
diagnostic_impl (richloc, NULL, -1, gmsgid, &ap, DK_ERROR);
va_end (ap);
}
@ -1530,7 +1610,7 @@ sorry (const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, input_location);
diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_SORRY);
diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_SORRY);
va_end (ap);
}
@ -1542,7 +1622,7 @@ sorry_at (location_t loc, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, loc);
diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_SORRY);
diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_SORRY);
va_end (ap);
}
@ -1564,7 +1644,7 @@ fatal_error (location_t loc, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, loc);
diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_FATAL);
diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_FATAL);
va_end (ap);
gcc_unreachable ();
@ -1581,7 +1661,7 @@ internal_error (const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, input_location);
diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ICE);
diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_ICE);
va_end (ap);
gcc_unreachable ();
@ -1597,7 +1677,7 @@ internal_error_no_backtrace (const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, input_location);
diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ICE_NOBT);
diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_ICE_NOBT);
va_end (ap);
gcc_unreachable ();

View File

@ -46,6 +46,10 @@ struct diagnostic_info
/* The location at which the diagnostic is to be reported. */
rich_location *richloc;
/* An optional bundle of metadata associated with the diagnostic
(or NULL). */
const diagnostic_metadata *metadata;
/* Auxiliary data for client. */
void *x_data;
/* The kind of diagnostic it is about. */
@ -126,6 +130,10 @@ struct diagnostic_context
/* Character used for caret diagnostics. */
char caret_chars[rich_location::STATICALLY_ALLOCATED_RANGES];
/* True if we should print any CWE identifiers associated with
diagnostics. */
bool show_cwe;
/* True if we should print the command line option which controls
each diagnostic, if known. */
bool show_option_requested;

View File

@ -277,6 +277,7 @@ Objective-C and Objective-C++ Dialects}.
-fdiagnostics-format=@r{[}text@r{|}json@r{]} @gol
-fno-diagnostics-show-option -fno-diagnostics-show-caret @gol
-fno-diagnostics-show-labels -fno-diagnostics-show-line-numbers @gol
-fno-diagnostics-show-cwe @gol
-fdiagnostics-minimum-margin-width=@var{width} @gol
-fdiagnostics-parseable-fixits -fdiagnostics-generate-patch @gol
-fdiagnostics-show-template-tree -fno-elide-type @gol
@ -4005,6 +4006,15 @@ as the types of expressions:
This option suppresses the printing of these labels (in the example above,
the vertical bars and the ``char *'' and ``long int'' text).
@item -fno-diagnostics-show-cwe
@opindex fno-diagnostics-show-cwe
@opindex fdiagnostics-show-cwe
Diagnostic messages can optionally have an associated
@url{https://cwe.mitre.org/index.html, CWE} identifier.
GCC itself does not do this for any of its diagnostics, but plugins may do so.
By default, if this information is present, it will be printed with
the diagnostic. This option suppresses the printing of this metadata.
@item -fno-diagnostics-show-line-numbers
@opindex fno-diagnostics-show-line-numbers
@opindex fdiagnostics-show-line-numbers

View File

@ -2407,6 +2407,10 @@ common_handle_option (struct gcc_options *opts,
dc->parseable_fixits_p = value;
break;
case OPT_fdiagnostics_show_cwe:
dc->show_cwe = value;
break;
case OPT_fdiagnostics_show_option:
dc->show_option_requested = value;
break;

View File

@ -1,3 +1,9 @@
2019-12-18 David Malcolm <dmalcolm@redhat.com>
* gcc.dg/plugin/diagnostic-test-metadata.c: New test.
* gcc.dg/plugin/diagnostic_plugin_test_metadata.c: New test plugin.
* gcc.dg/plugin/plugin.exp (plugin_test_list): Add them.
2019-12-19 Jakub Jelinek <jakub@redhat.com>
PR fortran/92977

View File

@ -0,0 +1,9 @@
/* { dg-do compile } */
extern char *gets (char *s);
void test_cwe (void)
{
char buf[1024];
gets (buf); /* { dg-warning "never use 'gets' \\\[CWE-242\\\]" } */
}

View File

@ -0,0 +1,140 @@
/* This plugin exercises diagnostic_metadata. */
#include "gcc-plugin.h"
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "stringpool.h"
#include "toplev.h"
#include "basic-block.h"
#include "hash-table.h"
#include "vec.h"
#include "ggc.h"
#include "basic-block.h"
#include "tree-ssa-alias.h"
#include "internal-fn.h"
#include "gimple-fold.h"
#include "tree-eh.h"
#include "gimple-expr.h"
#include "is-a.h"
#include "gimple.h"
#include "gimple-iterator.h"
#include "tree.h"
#include "tree-pass.h"
#include "intl.h"
#include "plugin-version.h"
#include "diagnostic.h"
#include "context.h"
#include "gcc-rich-location.h"
#include "diagnostic-metadata.h"
int plugin_is_GPL_compatible;
const pass_data pass_data_test_metadata =
{
GIMPLE_PASS, /* type */
"test_metadata", /* name */
OPTGROUP_NONE, /* optinfo_flags */
TV_NONE, /* tv_id */
PROP_ssa, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_test_metadata : public gimple_opt_pass
{
public:
pass_test_metadata(gcc::context *ctxt)
: gimple_opt_pass(pass_data_test_metadata, ctxt)
{}
/* opt_pass methods: */
bool gate (function *) { return true; }
virtual unsigned int execute (function *);
}; // class pass_test_metadata
/* Determine if STMT is a call with NUM_ARGS arguments to a function
named FUNCNAME.
If so, return STMT as a gcall *. Otherwise return NULL. */
static gcall *
check_for_named_call (gimple *stmt,
const char *funcname, unsigned int num_args)
{
gcc_assert (funcname);
gcall *call = dyn_cast <gcall *> (stmt);
if (!call)
return NULL;
tree fndecl = gimple_call_fndecl (call);
if (!fndecl)
return NULL;
if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname))
return NULL;
if (gimple_call_num_args (call) != num_args)
{
error_at (stmt->location, "expected number of args: %i (got %i)",
num_args, gimple_call_num_args (call));
return NULL;
}
return call;
}
/* Exercise diagnostic_metadata. */
unsigned int
pass_test_metadata::execute (function *fun)
{
gimple_stmt_iterator gsi;
basic_block bb;
FOR_EACH_BB_FN (bb, fun)
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
gimple *stmt = gsi_stmt (gsi);
/* Example of CWE: complain about uses of gets. */
if (gcall *call = check_for_named_call (stmt, "gets", 1))
{
gcc_rich_location richloc (gimple_location (call));
/* CWE-242: Use of Inherently Dangerous Function. */
diagnostic_metadata m;
m.add_cwe (242);
warning_at (&richloc, m, 0,
"never use %qs", "gets");
}
}
return 0;
}
int
plugin_init (struct plugin_name_args *plugin_info,
struct plugin_gcc_version *version)
{
struct register_pass_info pass_info;
const char *plugin_name = plugin_info->base_name;
int argc = plugin_info->argc;
struct plugin_argument *argv = plugin_info->argv;
if (!plugin_default_version_check (version, &gcc_version))
return 1;
pass_info.pass = new pass_test_metadata (g);
pass_info.reference_pass_name = "ssa";
pass_info.ref_pass_instance_number = 1;
pass_info.pos_op = PASS_POS_INSERT_AFTER;
register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
&pass_info);
return 0;
}

View File

@ -94,6 +94,7 @@ set plugin_test_list [list \
diagnostic-test-inlining-2.c \
diagnostic-test-inlining-3.c \
diagnostic-test-inlining-4.c } \
{ diagnostic_plugin_test_metadata.c diagnostic-test-metadata.c } \
{ location_overflow_plugin.c \
location-overflow-test-1.c \
location-overflow-test-2.c \

View File

@ -1179,6 +1179,8 @@ general_init (const char *argv0, bool init_signals)
= global_options_init.x_flag_diagnostics_show_labels;
global_dc->show_line_numbers_p
= global_options_init.x_flag_diagnostics_show_line_numbers;
global_dc->show_cwe
= global_options_init.x_flag_diagnostics_show_cwe;
global_dc->show_option_requested
= global_options_init.x_flag_diagnostics_show_option;
global_dc->min_margin_width