#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"
#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;
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;
diagnostic->message.format_spec = msg;
diagnostic->message.m_richloc = richloc;
diagnostic->richloc = richloc;
+ diagnostic->metadata = NULL;
diagnostic->kind = kind;
diagnostic->option_index = 0;
}
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. */
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);
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;
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)
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);
}
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;
}
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;
}
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
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);
}
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);
}
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);
}
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;
}
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;
}
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;
}
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);
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);
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;
}
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;
}
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;
}
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;
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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 ();
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 ();
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 ();
--- /dev/null
+/* 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;
+}