From patchwork Wed Jun 22 22:34:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 1646808 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=pdpPKcR3; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LSyxQ6mVMz9sGp for ; Thu, 23 Jun 2022 08:39:38 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DA1353830668 for ; Wed, 22 Jun 2022 22:39:36 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DA1353830668 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1655937576; bh=d1vEeh79ACL+mcuMqV8QCEEsjxMp73SRZ0xNXJx2OC0=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=pdpPKcR3YPbME8sZhSm2JsDDvZ5GXLntvJMGyOmsKQ3VIK1AharA7h13KD1nxT56q eHGzuyhpCkThP7Pq4/Xqc2aOI1tADUyT839ZcUgzjT8VXxIOgPGLH5HCYu0LO8li+7 JkWlj3Om3Mt1Uet1Y3vGbztCfW7DsgjhtltxRlRQ= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 6B90F3830670 for ; Wed, 22 Jun 2022 22:34:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 6B90F3830670 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-259-f9cqTIDhNByT_gOZoK_J3Q-1; Wed, 22 Jun 2022 18:34:49 -0400 X-MC-Unique: f9cqTIDhNByT_gOZoK_J3Q-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id D57DC101E9B0 for ; Wed, 22 Jun 2022 22:34:48 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.2.17.61]) by smtp.corp.redhat.com (Postfix) with ESMTP id ACDB51121314; Wed, 22 Jun 2022 22:34:48 +0000 (UTC) To: gcc-patches@gcc.gnu.org Subject: [PATCH 02/12] diagnostics: associate rules with plugins in SARIF output Date: Wed, 22 Jun 2022 18:34:37 -0400 Message-Id: <20220622223447.2462880-3-dmalcolm@redhat.com> In-Reply-To: <20220622223447.2462880-1-dmalcolm@redhat.com> References: <20220622223447.2462880-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: David Malcolm via Gcc-patches From: David Malcolm Reply-To: David Malcolm Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" gcc/ChangeLog: * diagnostic-client-data-hooks.h (class diagnostic_client_plugin_info): Move to... * diagnostic-client-plugin.h: ...this new file. * diagnostic-format-sarif.cc: Include "diagnostic-client-plugin.h". (class sarif_tool_component): New class. (sarif_builder::m_rule_id_set): Move field to sarif_tool_component. (sarif_builder::m_rules_arr): Likewise. (sarif_builder::m_driver_obj): New field. (sarif_builder::m_extensions_arr): New field. (sarif_builder::m_plugin_objs): New field. (sarif_tool_component::sarif_tool_component): New. (sarif_tool_component::lazily_add_rule): New. (sarif_builder::sarif_builder): Update for changes to fields. (sarif_builder::get_plugin_tool_component_object): New, adapted from code within sarif_builder::make_tool_object. (maybe_get_first_rule): New. (sarif_builder::set_result_rule_id): New, adapted from code within sarif_builder::make_result_object. (sarif_builder::make_result_object): Move rule_id logic to sarif_builder::set_result_rule_id. (sarif_builder::make_reporting_descriptor_object_for_rule): New. (sarif_builder::make_tool_object): Drop "const" qualifier. Use the m_driver_obj and m_extensions_arr created in the ctor. Update the visitor to call get_plugin_tool_component_object, rather than duplicate the toolComponent creation logic. (sarif_builder::make_driver_tool_component_object): Convert return type to sarif_tool_component *. Move setting of "rules" property to sarif_tool_component ctor. * diagnostic-metadata.h (class diagnostic_client_plugin_info): New forward decl. (diagnostic_metadata::diagnostic_metadata): Add overloaded ctor. Initialize m_plugin. (diagnostic_metadata::get_plugin): New. (diagnostic_metadata::m_plugin): New field. * doc/plugins.texi (Plugin initialization): Update. * plugin.cc: Include "diagnostic-client-plugin.h". (plugin_name_args::plugin_name_args): New ctor. (plugin_name_args::get_short_name): New. (plugin_name_args::get_full_name): New. (plugin_name_args::get_version): New. (add_new_plugin): Rewrite creation of "plugin" to use new with a ctor. * plugin.h: Include "diagnostic-client-plugin.h". (struct plugin_name_args): Convert to... (class plugin_name_args): ...this, deriving it from diagnostic_client_plugin_info. (plugin_name_args::plugin_name_args): New ctor decl. (plugin_name_args::get_short_name): New decl. (plugin_name_args::get_full_name): New decl. (plugin_name_args::get_version): New decl. * tree-diagnostic-client-data-hooks.cc: Include "diagnostic-client-plugin.h". (class compiler_diagnostic_client_plugin_info): Delete. (compiler_version_info::on_plugin_cb): Pass plugin_name_args to the visitor, now that the former is a diagnostic_client_plugin_info. gcc/testsuite/ChangeLog: * gcc.dg/plugin/diagnostic-test-metadata-sarif.c: New test. * gcc.dg/plugin/diagnostic_plugin_test_metadata.c (diag_plugin_info): New global. (pass_test_metadata::execute): Pass it to metadata. (plugin_init): Initialize it. * gcc.dg/plugin/plugin.exp (plugin_test_list): Add diagnostic-test-metadata-sarif.c to diagnostic_plugin_test_metadata.c. Signed-off-by: David Malcolm --- gcc/diagnostic-client-data-hooks.h | 18 -- gcc/diagnostic-client-plugin.h | 43 +++ gcc/diagnostic-format-sarif.cc | 283 +++++++++++++----- gcc/diagnostic-metadata.h | 22 +- gcc/doc/plugins.texi | 17 +- gcc/plugin.cc | 36 ++- gcc/plugin.h | 12 +- .../plugin/diagnostic-test-metadata-sarif.c | 39 +++ .../plugin/diagnostic_plugin_test_metadata.c | 6 +- gcc/testsuite/gcc.dg/plugin/plugin.exp | 4 +- gcc/tree-diagnostic-client-data-hooks.cc | 36 +-- 11 files changed, 382 insertions(+), 134 deletions(-) create mode 100644 gcc/diagnostic-client-plugin.h create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-sarif.c diff --git a/gcc/diagnostic-client-data-hooks.h b/gcc/diagnostic-client-data-hooks.h index ba78546abeb..03464202fe1 100644 --- a/gcc/diagnostic-client-data-hooks.h +++ b/gcc/diagnostic-client-data-hooks.h @@ -84,22 +84,4 @@ public: virtual void for_each_plugin (plugin_visitor &v) const = 0; }; -/* Abstract base class for a diagnostic_context to get at - information about a specific plugin within a client. */ - -class diagnostic_client_plugin_info -{ -public: - /* For use e.g. by SARIF "name" property (SARIF v2.1.0 section 3.19.8). */ - virtual const char *get_short_name () const = 0; - - /* For use e.g. by SARIF "fullName" property - (SARIF v2.1.0 section 3.19.9). */ - virtual const char *get_full_name () const = 0; - - /* For use e.g. by SARIF "version" property - (SARIF v2.1.0 section 3.19.13). */ - virtual const char *get_version () const = 0; -}; - #endif /* ! GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H */ diff --git a/gcc/diagnostic-client-plugin.h b/gcc/diagnostic-client-plugin.h new file mode 100644 index 00000000000..b0e266fac1b --- /dev/null +++ b/gcc/diagnostic-client-plugin.h @@ -0,0 +1,43 @@ +/* Metadata about plugins within a diagnostic client. + Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by David Malcolm + +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 +. */ + +#ifndef GCC_DIAGNOSTIC_CLIENT_PLUGIN_H +#define GCC_DIAGNOSTIC_CLIENT_PLUGIN_H + +/* Abstract base class for a diagnostic_context to get at + information about a specific plugin within a client, + and for associating plugins with diagnostic metadata. */ + +class diagnostic_client_plugin_info +{ +public: + /* For use e.g. by SARIF "name" property (SARIF v2.1.0 section 3.19.8). */ + virtual const char *get_short_name () const = 0; + + /* For use e.g. by SARIF "fullName" property + (SARIF v2.1.0 section 3.19.9). */ + virtual const char *get_full_name () const = 0; + + /* For use e.g. by SARIF "version" property + (SARIF v2.1.0 section 3.19.13). */ + virtual const char *get_version () const = 0; +}; + +#endif /* ! GCC_DIAGNOSTIC_CLIENT_PLUGIN_H */ diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc index a7bb9fb639d..a409abf648b 100644 --- a/gcc/diagnostic-format-sarif.cc +++ b/gcc/diagnostic-format-sarif.cc @@ -29,9 +29,26 @@ along with GCC; see the file COPYING3. If not see #include "cpplib.h" #include "logical-location.h" #include "diagnostic-client-data-hooks.h" +#include "diagnostic-client-plugin.h" class sarif_builder; +/* Subclass of json::object for SARIF toolComponent objects + (SARIF v2.1.0 section section 3.19), used for the driver + and for extensions. */ + +class sarif_tool_component : public json::object +{ +public: + sarif_tool_component (); + + void lazily_add_rule (char *id, json::object *reporting_desc_obj); + +private: + hash_set m_rule_id_set; + json::array *m_rules_arr; +}; + /* Subclass of json::object for SARIF result objects (SARIF v2.1.0 section 3.27. */ @@ -110,6 +127,13 @@ public: json::object *make_message_object (const char *msg) const; private: + sarif_tool_component * + get_plugin_tool_component_object + (const diagnostic_client_plugin_info *plugin); + void set_result_rule_id (diagnostic_context *context, + diagnostic_info *diagnostic, + diagnostic_t orig_diag_kind, + sarif_result *result_obj); sarif_result *make_result_object (diagnostic_context *context, diagnostic_info *diagnostic, diagnostic_t orig_diag_kind); @@ -133,12 +157,16 @@ private: json::object *make_multiformat_message_string (const char *msg) const; json::object *make_top_level_object (json::array *results); json::object *make_run_object (json::array *results); - json::object *make_tool_object () const; - json::object *make_driver_tool_component_object () const; + json::object *make_tool_object (); + sarif_tool_component *make_driver_tool_component_object () const; json::array *maybe_make_taxonomies_array () const; json::object *maybe_make_cwe_taxonomy_object () const; json::object *make_tool_component_reference_object_for_cwe () const; json::object * + make_reporting_descriptor_object_for_rule + (const diagnostic_metadata::rule &rule, + const char *desc); + json::object * make_reporting_descriptor_object_for_warning (diagnostic_context *context, diagnostic_info *diagnostic, diagnostic_t orig_diag_kind, @@ -168,8 +196,11 @@ private: hash_set m_filenames; bool m_seen_any_relative_paths; - hash_set m_rule_id_set; - json::array *m_rules_arr; + + sarif_tool_component *m_driver_obj; + json::array *m_extensions_arr; + hash_map m_plugin_objs; /* The set of all CWE IDs we've seen, if any. */ hash_set > m_cwe_id_set; @@ -179,6 +210,39 @@ private: static sarif_builder *the_builder; +/* class sarif_tool_component : public json::object. */ + +sarif_tool_component::sarif_tool_component () +: m_rule_id_set (), + m_rules_arr (new json::array ()) +{ + /* "rules" property (SARIF v2.1.0 section 3.19.23). */ + set ("rules", m_rules_arr); +} + +/* Take ownership of ID and REPORTING_DESC_OBJ. + Ensure that ID is represented within the rules array, + using REPORTING_DESC_OBJ if it isn't. */ + +void +sarif_tool_component::lazily_add_rule (char *id, + json::object *reporting_desc_obj) +{ + if (m_rule_id_set.contains (id)) + { + /* Already seen; clean up redundant entries. */ + free (id); + delete reporting_desc_obj; + } + else + { + /* This is the first time we've seen this ruleId. */ + /* Add to set, taking ownership. */ + m_rule_id_set.add (id); + m_rules_arr->append (reporting_desc_obj); + } +} + /* class sarif_result : public json::object. */ /* Handle secondary diagnostics that occur within a diagnostic group. @@ -221,10 +285,12 @@ sarif_builder::sarif_builder (diagnostic_context *context) m_results_array (new json::array ()), m_cur_group_result (NULL), m_seen_any_relative_paths (false), - m_rule_id_set (), - m_rules_arr (new json::array ()), + m_driver_obj (NULL), + m_extensions_arr (NULL), m_tabstop (context->tabstop) { + m_driver_obj = make_driver_tool_component_object (); + m_extensions_arr = new json::array (); } /* Implementation of "end_diagnostic" for SARIF output. */ @@ -320,51 +386,120 @@ make_rule_id_for_diagnostic_kind (diagnostic_t diag_kind) return rstrip; } -/* Make a result object (SARIF v2.1.0 section 3.27) for DIAGNOSTIC. */ +/* Get or create a toolComponent object (SARIF v2.1.0 section 3.19) + for PLUGIN, adding to m_extensions_arr and using m_plugin_objs to + reuse any existing object for PLUGIN. */ -sarif_result * -sarif_builder::make_result_object (diagnostic_context *context, +sarif_tool_component * +sarif_builder:: +get_plugin_tool_component_object (const diagnostic_client_plugin_info *plugin) +{ + if (sarif_tool_component **slot = m_plugin_objs.get (plugin)) + return *slot; + + sarif_tool_component *plugin_obj = new sarif_tool_component (); + m_plugin_objs.put (plugin, plugin_obj); + m_extensions_arr->append (plugin_obj); + + /* "name" property (SARIF v2.1.0 section 3.19.8). */ + if (const char *short_name = plugin->get_short_name ()) + plugin_obj->set ("name", new json::string (short_name)); + + /* "fullName" property (SARIF v2.1.0 section 3.19.9). */ + if (const char *full_name = plugin->get_full_name ()) + plugin_obj->set ("fullName", new json::string (full_name)); + + /* "version" property (SARIF v2.1.0 section 3.19.13). */ + if (const char *version = plugin->get_version ()) + plugin_obj->set ("version", new json::string (version)); + + return plugin_obj; +} + +/* If DIAGNOSTIC has any associated rules, get the first one. */ + +static const diagnostic_metadata::rule * +maybe_get_first_rule (diagnostic_info *diagnostic) +{ + if (!diagnostic->metadata) + return NULL; + if (diagnostic->metadata->get_num_rules () == 0) + return NULL; + return &diagnostic->metadata->get_rule (0); +} + +/* Set "ruleId" property of RESULT_OBJ (SARIF v2.1.0 section 3.27.5). + Ensure that there is such a rule within the component, and that such + a component exists (either for the driver, or any plugin). */ + +void +sarif_builder::set_result_rule_id (diagnostic_context *context, diagnostic_info *diagnostic, - diagnostic_t orig_diag_kind) + diagnostic_t orig_diag_kind, + sarif_result *result_obj) { - sarif_result *result_obj = new sarif_result (); + /* Determine which component we should search for within/add the + rule to. */ + sarif_tool_component *component_obj = m_driver_obj; + if (diagnostic->metadata) + if (const diagnostic_client_plugin_info *plugin + = diagnostic->metadata->get_plugin ()) + component_obj = get_plugin_tool_component_object (plugin); /* "ruleId" property (SARIF v2.1.0 section 3.27.5). */ - /* Ideally we'd have an option_name for these. */ + if (const diagnostic_metadata::rule *rule + = maybe_get_first_rule (diagnostic)) + if (char *desc = rule->make_description ()) + { + /* Lazily create reportingDescriptor objects for the rule + and add to the component. + Set ruleId referencing them. */ + result_obj->set ("ruleId", new json::string (desc)); + component_obj->lazily_add_rule + (desc, + make_reporting_descriptor_object_for_rule (*rule, desc)); + return; + } + + /* Otherwise, try to use the option_name for these. */ if (char *option_text = context->option_name (context, diagnostic->option_index, orig_diag_kind, diagnostic->kind)) { - /* Lazily create reportingDescriptor objects for and add to m_rules_arr. + /* Lazily create reportingDescriptor objects for the warning + and add to the component. Set ruleId referencing them. */ result_obj->set ("ruleId", new json::string (option_text)); - if (m_rule_id_set.contains (option_text)) - free (option_text); - else - { - /* This is the first time we've seen this ruleId. */ - /* Add to set, taking ownership. */ - m_rule_id_set.add (option_text); - - json::object *reporting_desc_obj - = make_reporting_descriptor_object_for_warning (context, - diagnostic, - orig_diag_kind, - option_text); - m_rules_arr->append (reporting_desc_obj); - } - } - else - { - /* Otherwise, we have an "error" or a stray "note"; use the - diagnostic kind as the ruleId, so that the result object at least - has a ruleId. - We don't bother creating reportingDescriptor objects for these. */ - char *rule_id = make_rule_id_for_diagnostic_kind (orig_diag_kind); - result_obj->set ("ruleId", new json::string (rule_id)); - free (rule_id); + component_obj->lazily_add_rule + (option_text, + make_reporting_descriptor_object_for_warning (context, + diagnostic, + orig_diag_kind, + option_text)); + return; } + /* Otherwise, we have a "warning" without an option, an "error" or a stray + "note"; use the diagnostic kind as the ruleId, so that the result object + at least has a ruleId. + We don't bother creating reportingDescriptor objects for these. */ + char *rule_id = make_rule_id_for_diagnostic_kind (orig_diag_kind); + result_obj->set ("ruleId", new json::string (rule_id)); + free (rule_id); +} + +/* Make a result object (SARIF v2.1.0 section 3.27) for DIAGNOSTIC. */ + +sarif_result * +sarif_builder::make_result_object (diagnostic_context *context, + diagnostic_info *diagnostic, + diagnostic_t orig_diag_kind) +{ + sarif_result *result_obj = new sarif_result (); + + /* "ruleId" property (SARIF v2.1.0 section 3.27.5). */ + set_result_rule_id (context, diagnostic, orig_diag_kind, result_obj); + /* "taxa" property (SARIF v2.1.0 section 3.27.8). */ if (diagnostic->metadata) if (int cwe_id = diagnostic->metadata->get_cwe ()) @@ -424,6 +559,32 @@ sarif_builder::make_result_object (diagnostic_context *context, return result_obj; } +/* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49) + for RULE, with DESC. */ + +json::object * +sarif_builder:: +make_reporting_descriptor_object_for_rule (const diagnostic_metadata::rule &rule, + const char *desc) +{ + json::object *reporting_desc = new json::object (); + + /* "id" property (SARIF v2.1.0 section 3.49.3). */ + reporting_desc->set ("id", new json::string (desc)); + + /* We don't implement "name" property (SARIF v2.1.0 section 3.49.7), since + it seems redundant compared to "id". */ + + /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */ + if (char *url = rule.make_url ()) + { + reporting_desc->set ("helpUri", new json::string (url)); + free (url); + } + + return reporting_desc; +} + /* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49) for a GCC warning. */ @@ -1089,16 +1250,16 @@ sarif_builder::make_run_object (json::array *results) /* Make a tool object (SARIF v2.1.0 section 3.18). */ json::object * -sarif_builder::make_tool_object () const +sarif_builder::make_tool_object () { json::object *tool_obj = new json::object (); /* "driver" property (SARIF v2.1.0 section 3.18.2). */ - json::object *driver_obj = make_driver_tool_component_object (); - tool_obj->set ("driver", driver_obj); + tool_obj->set ("driver", m_driver_obj); /* Report plugins via the "extensions" property (SARIF v2.1.0 section 3.18.3). */ + tool_obj->set ("extensions", m_extensions_arr); if (m_context->m_client_data_hooks) if (const client_version_info *vinfo = m_context->m_client_data_hooks->get_any_version_info ()) @@ -1106,36 +1267,19 @@ sarif_builder::make_tool_object () const class my_plugin_visitor : public client_version_info :: plugin_visitor { public: + my_plugin_visitor (sarif_builder *builder) + : m_builder (builder) + {} + void on_plugin (const diagnostic_client_plugin_info &p) final override { - /* Create a toolComponent object (SARIF v2.1.0 section 3.19) - for the plugin. */ - json::object *plugin_obj = new json::object (); - m_plugin_objs.safe_push (plugin_obj); - - /* "name" property (SARIF v2.1.0 section 3.19.8). */ - if (const char *short_name = p.get_short_name ()) - plugin_obj->set ("name", new json::string (short_name)); - - /* "fullName" property (SARIF v2.1.0 section 3.19.9). */ - if (const char *full_name = p.get_full_name ()) - plugin_obj->set ("fullName", new json::string (full_name)); - - /* "version" property (SARIF v2.1.0 section 3.19.13). */ - if (const char *version = p.get_version ()) - plugin_obj->set ("version", new json::string (version)); + m_builder->get_plugin_tool_component_object (&p); } - auto_vec m_plugin_objs; + private: + sarif_builder *m_builder; }; - my_plugin_visitor v; + my_plugin_visitor v (this); vinfo->for_each_plugin (v); - if (v.m_plugin_objs.length () > 0) - { - json::array *extensions_arr = new json::array (); - tool_obj->set ("extensions", extensions_arr); - for (auto iter : v.m_plugin_objs) - extensions_arr->append (iter); - } } /* Perhaps we could also show GMP, MPFR, MPC, isl versions as other @@ -1147,10 +1291,10 @@ sarif_builder::make_tool_object () const /* Make a toolComponent object (SARIF v2.1.0 section 3.19) for what SARIF calls the "driver" (see SARIF v2.1.0 section 3.18.1). */ -json::object * +sarif_tool_component * sarif_builder::make_driver_tool_component_object () const { - json::object *driver_obj = new json::object (); + sarif_tool_component *driver_obj = new sarif_tool_component (); if (m_context->m_client_data_hooks) if (const client_version_info *vinfo @@ -1179,9 +1323,6 @@ sarif_builder::make_driver_tool_component_object () const } } - /* "rules" property (SARIF v2.1.0 section 3.19.23). */ - driver_obj->set ("rules", m_rules_arr); - return driver_obj; } diff --git a/gcc/diagnostic-metadata.h b/gcc/diagnostic-metadata.h index 80017d35fa9..dce6763a1d9 100644 --- a/gcc/diagnostic-metadata.h +++ b/gcc/diagnostic-metadata.h @@ -21,11 +21,16 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_DIAGNOSTIC_METADATA_H #define GCC_DIAGNOSTIC_METADATA_H +class diagnostic_client_plugin_info; + /* A bundle of additional metadata that can be associated with a diagnostic. - This supports an optional CWE identifier, and zero or more - "rules". */ + This supports: + - an optional plugin associated with this diagnostic + - an optional CWE identifier + - zero or more "rules" (such as rules within a coding standard, + or within a specification). */ class diagnostic_metadata { @@ -62,7 +67,15 @@ class diagnostic_metadata const char *m_url; }; - diagnostic_metadata () : m_cwe (0) {} + /* Ctors. */ + diagnostic_metadata () + : m_plugin (NULL), + m_cwe (0) + {} + diagnostic_metadata (const diagnostic_client_plugin_info *plugin) + : m_plugin (plugin), + m_cwe (0) + {} void add_cwe (int cwe) { m_cwe = cwe; } int get_cwe () const { return m_cwe; } @@ -74,10 +87,13 @@ class diagnostic_metadata m_rules.safe_push (&r); } + const diagnostic_client_plugin_info *get_plugin () const { return m_plugin; } + unsigned get_num_rules () const { return m_rules.length (); } const rule &get_rule (unsigned idx) const { return *(m_rules[idx]); } private: + const diagnostic_client_plugin_info *m_plugin; int m_cwe; auto_vec m_rules; }; diff --git a/gcc/doc/plugins.texi b/gcc/doc/plugins.texi index 6d1a5fa7607..a1713901314 100644 --- a/gcc/doc/plugins.texi +++ b/gcc/doc/plugins.texi @@ -102,11 +102,20 @@ the parser. The arguments to @code{plugin_init} are: @item @code{version}: GCC version. @end itemize -The @code{plugin_info} struct is defined as follows: +The @code{plugin_info} class is defined as follows: @smallexample -struct plugin_name_args +class plugin_name_args : public diagnostic_client_plugin_info @{ + public: + plugin_name_args (char *base_name_, + const char *full_name_); + + /* Implementation of diagnostic_client_plugin_info. */ + const char *get_short_name () const final override; + const char *get_full_name () const final override; + const char *get_version () const final override; + char *base_name; /* Short name of the plugin (filename without .so suffix). */ const char *full_name; /* Path to the plugin as specified with @@ -149,7 +158,7 @@ recommended version check to perform looks like ... int -plugin_init (struct plugin_name_args *plugin_info, +plugin_init (plugin_name_args *plugin_info, struct plugin_gcc_version *version) @{ if (!plugin_default_version_check (version, &gcc_version)) @@ -295,7 +304,7 @@ struct register_pass_info /* Sample plugin code that registers a new pass. */ int -plugin_init (struct plugin_name_args *plugin_info, +plugin_init (plugin_name_args *plugin_info, struct plugin_gcc_version *version) @{ struct register_pass_info pass_info; diff --git a/gcc/plugin.cc b/gcc/plugin.cc index 6c42e057cbc..19cc74867d3 100644 --- a/gcc/plugin.cc +++ b/gcc/plugin.cc @@ -26,6 +26,7 @@ along with GCC; see the file COPYING3. If not see #include "options.h" #include "tree-pass.h" #include "diagnostic-core.h" +#include "diagnostic-client-plugin.h" #include "flags.h" #include "intl.h" #include "plugin.h" @@ -124,6 +125,39 @@ static const char *str_plugin_init_func_name = "plugin_init"; static const char *str_license = "plugin_is_GPL_compatible"; #endif +/* class plugin_name_args : public diagnostic_client_plugin_info. */ + +/* plugin_name_args's ctor. */ + +plugin_name_args::plugin_name_args (char *base_name_, + const char *full_name_) +: base_name (base_name_), + full_name (full_name_), + argc (0), + argv (NULL), + version (NULL), + help (NULL) +{ +} + +const char * +plugin_name_args::get_short_name () const +{ + return base_name; +} + +const char * +plugin_name_args::get_full_name () const +{ + return full_name; +} + +const char * +plugin_name_args::get_version () const +{ + return version; +} + /* Helper function for hashing the base_name of the plugin_name_args structure to be inserted into the hash table. */ @@ -236,7 +270,7 @@ add_new_plugin (const char* plugin_name) return; } - plugin = XCNEW (struct plugin_name_args); + plugin = new plugin_name_args (base_name, plugin_name); plugin->base_name = base_name; plugin->full_name = plugin_name; diff --git a/gcc/plugin.h b/gcc/plugin.h index e7e8b51d15a..f5d22a8f53b 100644 --- a/gcc/plugin.h +++ b/gcc/plugin.h @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see #define PLUGIN_H #include "highlev-plugin-common.h" +#include "diagnostic-client-plugin.h" /* Event names. */ enum plugin_event @@ -65,8 +66,17 @@ struct plugin_gcc_version }; /* Object that keeps track of the plugin name and its arguments. */ -struct plugin_name_args +class plugin_name_args : public diagnostic_client_plugin_info { + public: + plugin_name_args (char *base_name_, + const char *full_name_); + + /* Implementation of diagnostic_client_plugin_info. */ + const char *get_short_name () const final override; + const char *get_full_name () const final override; + const char *get_version () const final override; + char *base_name; /* Short name of the plugin (filename without .so suffix). */ const char *full_name; /* Path to the plugin as specified with diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-sarif.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-sarif.c new file mode 100644 index 00000000000..ac8f4ba2d83 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-sarif.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=sarif-file" } */ + +extern char *gets (char *s); + +void test_cwe (void) +{ + char buf[1024]; + gets (buf); +} + +/* Verify that some JSON was written to a file with the expected name. */ + +/* We expect various properties. + The indentation here reflects the expected hierarchy, though these tests + don't check for that, merely the string fragments we expect. + { dg-final { scan-sarif-file "\"version\": \"2.1.0\"" } } + { dg-final { scan-sarif-file "\"runs\": \\\[" } } + { dg-final { scan-sarif-file "\"tool\": " } } + { dg-final { scan-sarif-file "\"driver\": " } } + { dg-final { scan-sarif-file "\"name\": \"GNU C" } } + + { dg-final { scan-sarif-file "\"rules\": \\\[" } } + { dg-final { scan-sarif-file "\"id\": \"STR34-C\"" } } + { dg-final { scan-sarif-file "\"helpUri\": \"https://example.com/\"" } } + + Ideally we would verify that the above rule is within the extension, + rather than the driver. Unfortunately we don't have a way to + do this at present. + + { dg-final { scan-sarif-file "\"extensions\": \\\[" } } + { dg-final { scan-sarif-file "\"name\": \"diagnostic_plugin_test_metadata\"" } } + { dg-final { scan-sarif-file "\"results\": \\\[" } } + { dg-final { scan-sarif-file "\"level\": \"warning\"" } } + { dg-final { scan-sarif-file "\"message\": " } } + { dg-final { scan-sarif-file "\"text\": \"never use 'gets'\"" } } + { dg-final { scan-sarif-file "\"taxa\": \\\[" } } + { dg-final { scan-sarif-file "\"id\": \"242\"" } } +*/ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.c index b86a8b3650e..b2a86e1bc68 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.c @@ -32,6 +32,8 @@ int plugin_is_GPL_compatible; +static diagnostic_client_plugin_info *diag_plugin_info; + const pass_data pass_data_test_metadata = { GIMPLE_PASS, /* type */ @@ -106,7 +108,7 @@ pass_test_metadata::execute (function *fun) if (gcall *call = check_for_named_call (stmt, "gets", 1)) { gcc_rich_location richloc (gimple_location (call)); - diagnostic_metadata m; + diagnostic_metadata m (diag_plugin_info); /* CWE-242: Use of Inherently Dangerous Function. */ m.add_cwe (242); @@ -136,6 +138,8 @@ plugin_init (struct plugin_name_args *plugin_info, if (!plugin_default_version_check (version, &gcc_version)) return 1; + diag_plugin_info = plugin_info; + pass_info.pass = new pass_test_metadata (g); pass_info.reference_pass_name = "ssa"; pass_info.ref_pass_instance_number = 1; diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp index 63b117d3cde..2244f52211d 100644 --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp @@ -96,7 +96,9 @@ 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 } \ + { diagnostic_plugin_test_metadata.c \ + diagnostic-test-metadata.c \ + diagnostic-test-metadata-sarif.c } \ { diagnostic_plugin_test_paths.c \ diagnostic-test-paths-1.c \ diagnostic-test-paths-2.c \ diff --git a/gcc/tree-diagnostic-client-data-hooks.cc b/gcc/tree-diagnostic-client-data-hooks.cc index f8ff271d2f5..c58df1fe70c 100644 --- a/gcc/tree-diagnostic-client-data-hooks.cc +++ b/gcc/tree-diagnostic-client-data-hooks.cc @@ -27,41 +27,10 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic.h" #include "tree-logical-location.h" #include "diagnostic-client-data-hooks.h" +#include "diagnostic-client-plugin.h" #include "langhooks.h" #include "plugin.h" -/* Concrete class for supplying a diagnostic_context with information - about a specific plugin within the client, when the client is the - compiler (i.e. a GCC plugin). */ - -class compiler_diagnostic_client_plugin_info - : public diagnostic_client_plugin_info -{ -public: - compiler_diagnostic_client_plugin_info (const plugin_name_args *args) - : m_args (args) - { - } - - const char *get_short_name () const final override - { - return m_args->base_name; - } - - const char *get_full_name () const final override - { - return m_args->full_name; - } - - const char *get_version () const final override - { - return m_args->version; - } - -private: - const plugin_name_args *m_args; -}; - /* Concrete subclass of client_version_info for use by compilers proper, (i.e. using lang_hooks, and with knowledge of GCC plugins). */ @@ -103,10 +72,9 @@ private: on_plugin_cb (const plugin_name_args *args, void *user_data) { - compiler_diagnostic_client_plugin_info cpi (args); client_version_info::plugin_visitor *visitor = (client_version_info::plugin_visitor *)user_data; - visitor->on_plugin (cpi); + visitor->on_plugin (*args); } };