From patchwork Wed Mar 15 22:20:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 1757621 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=) Authentication-Results: legolas.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=vReZOmCX; dkim-atps=neutral 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 ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PcPx145vMz1yWp for ; Thu, 16 Mar 2023 09:20:51 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A962B3857C45 for ; Wed, 15 Mar 2023 22:20:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A962B3857C45 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1678918849; bh=SQw8mzQdsijox7PEOv8tKg/bBKHNtTYiB5EjAqWLTwo=; h=To:Cc:Subject:Date:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=vReZOmCXcc2n0veFW3DvqfRsG2aghmewsNOSomy6JeqHOK8fRCJBOa6l9T6ynt2/b n7RATh8VNpqdoXg4JDHChIXJvHkcoalcWikkaOd/0YohhAPR0w/HV5hkhfKvkWF6tb Xeb2RfeI1w3BARSuSL24Ot2nHGFEFohpwH87Gslo= 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 445D73858C78 for ; Wed, 15 Mar 2023 22:20:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 445D73858C78 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-197-wGNZ9ZhdNkuNlkV0c14xXg-1; Wed, 15 Mar 2023 18:20:25 -0400 X-MC-Unique: wGNZ9ZhdNkuNlkV0c14xXg-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 293A9101A531 for ; Wed, 15 Mar 2023 22:20:25 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.2.17.70]) by smtp.corp.redhat.com (Postfix) with ESMTP id A9A6E2027040; Wed, 15 Mar 2023 22:20:24 +0000 (UTC) To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [pushed] diagnostics: attempt to capture crash info in SARIF output [PR109097] Date: Wed, 15 Mar 2023 18:20:22 -0400 Message-Id: <20230315222022.3505853-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.4 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP 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" As noted in PR analyzer/109097, if an internal compiler error occurs when -fdiagnostics-format=sarif-file is specified, we currently fail to write out a .sarif file, and the output to stderr doesn't contain "internal compiler error" or "Internal compiler error"; just the backtrace if we're lucky, and the "Please submit a full bug report" messages. This is a nuisance e.g. for my integration testing of -fanalyzer, where I'm gathering the results of builds via the .sarif output: if it crashes on a particular source file, then no output is generated, and it's effectively silent about the crash. This patch fixes things by adding a callback to diagnostic_context so that the SARIF output code can make one final attempt to write its output if an ICE occurs. It also special-cases the output, so that an ICE is treated as an "error"-level "notification" relating to the operation of the tool (SARIF v2.1.0 section 3.58), rather than a "result" about the code being analyzed by the tool. The patch adds test coverage for this via a plugin that can inject: * calls to internal_compiler_error, and * writes through a NULL pointer and verifying that a .sarif file is written out capturing the crash (and also that an ICE occurs via dg-ice, which seems to treat the ICE as an XFAIL, which is reasonable). I've added support for this to my integration-testing scripts: testing shows that with this patch we capture analyzer crashes in .sarif files (specifically, the analyzer crash on qemu: PR analyzer/109094), and I've updated my scripts to work with and report such output. I manually verified that the resulting .sarif files validate against the schema. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to trunk as r13-6701-g79aaba0a71f34a. gcc/ChangeLog: PR analyzer/109097 * diagnostic-format-sarif.cc (class sarif_invocation): New. (class sarif_ice_notification): New. (sarif_builder::m_invocation_obj): New field. (sarif_invocation::add_notification_for_ice): New. (sarif_invocation::prepare_to_flush): New. (sarif_ice_notification::sarif_ice_notification): New. (sarif_builder::sarif_builder): Add m_invocation_obj. (sarif_builder::end_diagnostic): Special-case DK_ICE and DK_ICE_NOBT. (sarif_builder::flush_to_file): Call prepare_to_flush on m_invocation_obj. Pass the latter to make_top_level_object. (sarif_builder::make_result_object): Move creation of "locations" array to... (sarif_builder::make_locations_arr): ...this new function. (sarif_builder::make_top_level_object): Add "invocation_obj" param and pass it to make_run_object. (sarif_builder::make_run_object): Add "invocation_obj" param and use it. (sarif_ice_handler): New callback. (diagnostic_output_format_init_sarif): Wire up sarif_ice_handler. * diagnostic.cc (diagnostic_initialize): Initialize new field "ice_handler_cb". (diagnostic_action_after_output): If it is set, make one attempt to call ice_handler_cb. * diagnostic.h (diagnostic_context::ice_handler_cb): New field. gcc/testsuite/ChangeLog: PR analyzer/109097 * c-c++-common/diagnostic-format-sarif-file-1.c: Verify that we have an invocation object marked as succeeding, with no notifications. * gcc.dg/plugin/crash-test-ice-sarif.c: New test. * gcc.dg/plugin/crash-test-ice-stderr.c: New test. * gcc.dg/plugin/crash-test-write-though-null-sarif.c: New test. * gcc.dg/plugin/crash-test-write-though-null-stderr.c: New test. * gcc.dg/plugin/crash_test_plugin.c: New plugin. * gcc.dg/plugin/plugin.exp (plugin_test_list): Add the new plugin and test cases. Signed-off-by: David Malcolm --- gcc/diagnostic-format-sarif.cc | 173 ++++++++++++++++-- gcc/diagnostic.cc | 13 ++ gcc/diagnostic.h | 3 + .../diagnostic-format-sarif-file-1.c | 5 + .../gcc.dg/plugin/crash-test-ice-sarif.c | 62 +++++++ .../gcc.dg/plugin/crash-test-ice-stderr.c | 9 + .../crash-test-write-though-null-sarif.c | 62 +++++++ .../crash-test-write-though-null-stderr.c | 9 + .../gcc.dg/plugin/crash_test_plugin.c | 135 ++++++++++++++ gcc/testsuite/gcc.dg/plugin/plugin.exp | 5 + 10 files changed, 458 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/plugin/crash-test-ice-sarif.c create mode 100644 gcc/testsuite/gcc.dg/plugin/crash-test-ice-stderr.c create mode 100644 gcc/testsuite/gcc.dg/plugin/crash-test-write-though-null-sarif.c create mode 100644 gcc/testsuite/gcc.dg/plugin/crash-test-write-though-null-stderr.c create mode 100644 gcc/testsuite/gcc.dg/plugin/crash_test_plugin.c diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc index f8fdd586ff0..2c48cbd46e2 100644 --- a/gcc/diagnostic-format-sarif.cc +++ b/gcc/diagnostic-format-sarif.cc @@ -32,8 +32,29 @@ along with GCC; see the file COPYING3. If not see class sarif_builder; +/* Subclass of json::object for SARIF invocation objects + (SARIF v2.1.0 section 3.20). */ + +class sarif_invocation : public json::object +{ +public: + sarif_invocation () + : m_notifications_arr (new json::array ()), + m_success (true) + {} + + void add_notification_for_ice (diagnostic_context *context, + diagnostic_info *diagnostic, + sarif_builder *builder); + void prepare_to_flush (); + +private: + json::array *m_notifications_arr; + bool m_success; +}; + /* Subclass of json::object for SARIF result objects - (SARIF v2.1.0 section 3.27. */ + (SARIF v2.1.0 section 3.27). */ class sarif_result : public json::object { @@ -50,6 +71,20 @@ private: json::array *m_related_locations_arr; }; +/* Subclass of json::object for SARIF notification objects + (SARIF v2.1.0 section 3.58). + + This subclass is specifically for notifying when an + internal compiler error occurs. */ + +class sarif_ice_notification : public json::object +{ +public: + sarif_ice_notification (diagnostic_context *context, + diagnostic_info *diagnostic, + sarif_builder *builder); +}; + /* A class for managing SARIF output (for -fdiagnostics-format=sarif-stderr and -fdiagnostics-format=sarif-file). @@ -105,6 +140,7 @@ public: void flush_to_file (FILE *outf); + json::array *make_locations_arr (diagnostic_info *diagnostic); json::object *make_location_object (const rich_location &rich_loc, const logical_location *logical_loc); json::object *make_message_object (const char *msg) const; @@ -131,8 +167,10 @@ private: json::object *maybe_make_region_object_for_context (location_t loc) const; json::object *make_region_object_for_hint (const fixit_hint &hint) const; 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_top_level_object (sarif_invocation *invocation_obj, + json::array *results); + json::object *make_run_object (sarif_invocation *invocation_obj, + json::array *results); json::object *make_tool_object () const; json::object *make_driver_tool_component_object () const; json::array *maybe_make_taxonomies_array () const; @@ -159,6 +197,9 @@ private: diagnostic_context *m_context; + /* The JSON object for the invocation object. */ + sarif_invocation *m_invocation_obj; + /* The JSON array of pending diagnostics. */ json::array *m_results_array; @@ -179,6 +220,33 @@ private: static sarif_builder *the_builder; +/* class sarif_invocation : public json::object. */ + +/* Handle an internal compiler error DIAGNOSTIC occurring on CONTEXT. + Add an object representing the ICE to the notifications array. */ + +void +sarif_invocation::add_notification_for_ice (diagnostic_context *context, + diagnostic_info *diagnostic, + sarif_builder *builder) +{ + m_success = false; + + sarif_ice_notification *notification_obj + = new sarif_ice_notification (context, diagnostic, builder); + m_notifications_arr->append (notification_obj); +} + +void +sarif_invocation::prepare_to_flush () +{ + /* "executionSuccessful" property (SARIF v2.1.0 section 3.20.14). */ + set ("executionSuccessful", new json::literal (m_success)); + + /* "toolExecutionNotifications" property (SARIF v2.1.0 section 3.20.21). */ + set ("toolExecutionNotifications", m_notifications_arr); +} + /* class sarif_result : public json::object. */ /* Handle secondary diagnostics that occur within a diagnostic group. @@ -212,12 +280,36 @@ sarif_result::on_nested_diagnostic (diagnostic_context *context, m_related_locations_arr->append (location_obj); } +/* class sarif_ice_notification : public json::object. */ + +/* sarif_ice_notification's ctor. + DIAGNOSTIC is an internal compiler error. */ + +sarif_ice_notification::sarif_ice_notification (diagnostic_context *context, + diagnostic_info *diagnostic, + sarif_builder *builder) +{ + /* "locations" property (SARIF v2.1.0 section 3.58.4). */ + json::array *locations_arr = builder->make_locations_arr (diagnostic); + set ("locations", locations_arr); + + /* "message" property (SARIF v2.1.0 section 3.85.5). */ + json::object *message_obj + = builder->make_message_object (pp_formatted_text (context->printer)); + pp_clear_output_area (context->printer); + set ("message", message_obj); + + /* "level" property (SARIF v2.1.0 section 3.58.6). */ + set ("level", new json::string ("error")); +} + /* class sarif_builder. */ /* sarif_builder's ctor. */ sarif_builder::sarif_builder (diagnostic_context *context) : m_context (context), + m_invocation_obj (new sarif_invocation ()), m_results_array (new json::array ()), m_cur_group_result (NULL), m_seen_any_relative_paths (false), @@ -234,6 +326,11 @@ sarif_builder::end_diagnostic (diagnostic_context *context, diagnostic_info *diagnostic, diagnostic_t orig_diag_kind) { + if (diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT) + { + m_invocation_obj->add_notification_for_ice (context, diagnostic, this); + return; + } if (m_cur_group_result) /* Nested diagnostic. */ @@ -267,8 +364,10 @@ sarif_builder::end_group () void sarif_builder::flush_to_file (FILE *outf) { - json::object *top = make_top_level_object (m_results_array); + m_invocation_obj->prepare_to_flush (); + json::object *top = make_top_level_object (m_invocation_obj, m_results_array); top->dump (outf); + m_invocation_obj = NULL; m_results_array = NULL; fprintf (outf, "\n"); delete top; @@ -387,15 +486,7 @@ sarif_builder::make_result_object (diagnostic_context *context, result_obj->set ("message", message_obj); /* "locations" property (SARIF v2.1.0 section 3.27.12). */ - json::array *locations_arr = new json::array (); - const logical_location *logical_loc = NULL; - if (m_context->m_client_data_hooks) - logical_loc - = m_context->m_client_data_hooks->get_current_logical_location (); - - json::object *location_obj - = make_location_object (*diagnostic->richloc, logical_loc); - locations_arr->append (location_obj); + json::array *locations_arr = make_locations_arr (diagnostic); result_obj->set ("locations", locations_arr); /* "codeFlows" property (SARIF v2.1.0 section 3.27.18). */ @@ -525,6 +616,25 @@ make_tool_component_reference_object_for_cwe () const return comp_ref_obj; } +/* Make an array suitable for use as the "locations" property of: + - a "result" object (SARIF v2.1.0 section 3.27.12), or + - a "notification" object (SARIF v2.1.0 section 3.58.4). */ + +json::array * +sarif_builder::make_locations_arr (diagnostic_info *diagnostic) +{ + json::array *locations_arr = new json::array (); + const logical_location *logical_loc = NULL; + if (m_context->m_client_data_hooks) + logical_loc + = m_context->m_client_data_hooks->get_current_logical_location (); + + json::object *location_obj + = make_location_object (*diagnostic->richloc, logical_loc); + locations_arr->append (location_obj); + return locations_arr; +} + /* If LOGICAL_LOC is non-NULL, use it to create a "logicalLocations" property within LOCATION_OBJ (SARIF v2.1.0 section 3.28.4). */ @@ -1023,10 +1133,11 @@ sarif_builder::make_multiformat_message_string (const char *msg) const #define SARIF_VERSION "2.1.0" /* Make a top-level sarifLog object (SARIF v2.1.0 section 3.13). - Take ownership of RESULTS. */ + Take ownership of INVOCATION_OBJ and RESULTS. */ json::object * -sarif_builder::make_top_level_object (json::array *results) +sarif_builder::make_top_level_object (sarif_invocation *invocation_obj, + json::array *results) { json::object *log_obj = new json::object (); @@ -1038,7 +1149,7 @@ sarif_builder::make_top_level_object (json::array *results) /* "runs" property (SARIF v2.1.0 section 3.13.4). */ json::array *run_arr = new json::array (); - json::object *run_obj = make_run_object (results); + json::object *run_obj = make_run_object (invocation_obj, results); run_arr->append (run_obj); log_obj->set ("runs", run_arr); @@ -1046,10 +1157,11 @@ sarif_builder::make_top_level_object (json::array *results) } /* Make a run object (SARIF v2.1.0 section 3.14). - Take ownership of RESULTS. */ + Take ownership of INVOCATION_OBJ and RESULTS. */ json::object * -sarif_builder::make_run_object (json::array *results) +sarif_builder::make_run_object (sarif_invocation *invocation_obj, + json::array *results) { json::object *run_obj = new json::object (); @@ -1061,6 +1173,13 @@ sarif_builder::make_run_object (json::array *results) if (json::array *taxonomies_arr = maybe_make_taxonomies_array ()) run_obj->set ("taxonomies", taxonomies_arr); + /* "invocations" property (SARIF v2.1.0 section 3.14.11). */ + { + json::array *invocations_arr = new json::array (); + invocations_arr->append (invocation_obj); + run_obj->set ("invocations", invocations_arr); + } + /* "originalUriBaseIds (SARIF v2.1.0 section 3.14.14). */ if (m_seen_any_relative_paths) { @@ -1538,6 +1657,23 @@ sarif_file_final_cb (diagnostic_context *) free (filename); } +/* Callback for diagnostic_context::ice_handler_cb for when an ICE + occurs. */ + +static void +sarif_ice_handler (diagnostic_context *context) +{ + /* Attempt to ensure that a .sarif file is written out. */ + diagnostic_finish (context); + + /* Print a header for the remaining output to stderr, and + return, attempting to print the usual ICE messages to + stderr. Hopefully this will be helpful to the user in + indicating what's gone wrong (also for DejaGnu, for pruning + those messages). */ + fnotice (stderr, "Internal compiler error:\n"); +} + /* Populate CONTEXT in preparation for SARIF output (either to stderr, or to a file). */ @@ -1552,6 +1688,7 @@ diagnostic_output_format_init_sarif (diagnostic_context *context) context->begin_group_cb = sarif_begin_group; context->end_group_cb = sarif_end_group; context->print_path = NULL; /* handled in sarif_end_diagnostic. */ + context->ice_handler_cb = sarif_ice_handler; /* The metadata is handled in SARIF format, rather than as text. */ context->show_cwe = false; diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc index c90c14e993e..0f093081161 100644 --- a/gcc/diagnostic.cc +++ b/gcc/diagnostic.cc @@ -241,6 +241,7 @@ diagnostic_initialize (diagnostic_context *context, int n_opts) context->begin_group_cb = NULL; context->end_group_cb = NULL; context->final_cb = default_diagnostic_final_cb; + context->ice_handler_cb = NULL; context->includes_seen = NULL; context->m_client_data_hooks = NULL; } @@ -665,6 +666,18 @@ diagnostic_action_after_output (diagnostic_context *context, case DK_ICE: case DK_ICE_NOBT: { + /* Optional callback for attempting to handle ICEs gracefully. */ + if (void (*ice_handler_cb) (diagnostic_context *) + = context->ice_handler_cb) + { + /* Clear the callback, to avoid potentially re-entering + the routine if there's a crash within the handler. */ + context->ice_handler_cb = NULL; + ice_handler_cb (context); + } + /* The context might have had diagnostic_finish called on + it at this point. */ + struct backtrace_state *state = NULL; if (diag_kind == DK_ICE) state = backtrace_create_state (NULL, 0, bt_err_callback, NULL); diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index e7390e49554..9a51097f146 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -405,6 +405,9 @@ struct diagnostic_context of a diagnostic's location. */ void (*set_locations_cb)(diagnostic_context *, diagnostic_info *); + /* Optional callback for attempting to handle ICEs gracefully. */ + void (*ice_handler_cb) (diagnostic_context *context); + /* Include files that diagnostic_report_current_module has already listed the include path for. */ hash_set *includes_seen; diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-1.c b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-1.c index 4d19ae14bb4..cad53095478 100644 --- a/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-1.c +++ b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-1.c @@ -24,6 +24,11 @@ { dg-final { scan-sarif-file "\"name\": \"GNU C" } } { dg-final { scan-sarif-file "\"fullName\": \"GNU C" } } { dg-final { scan-sarif-file "\"informationUri\": \"" } } + + { dg-final { scan-sarif-file "\"invocations\": \\\[" } } + { dg-final { scan-sarif-file "\"toolExecutionNotifications\": \\\[\\\]" } } + { dg-final { scan-sarif-file "\"executionSuccessful\": true" } } + { dg-final { scan-sarif-file "\"results\": \\\[" } } { dg-final { scan-sarif-file "\"level\": \"warning\"" } } { dg-final { scan-sarif-file "\"ruleId\": \"-Wcpp\"" } } diff --git a/gcc/testsuite/gcc.dg/plugin/crash-test-ice-sarif.c b/gcc/testsuite/gcc.dg/plugin/crash-test-ice-sarif.c new file mode 100644 index 00000000000..9186a3262ca --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/crash-test-ice-sarif.c @@ -0,0 +1,62 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=sarif-file" } */ + +extern void inject_ice (void); + +void test_inject_ice (void) +{ + inject_ice (); /* { dg-ice "" } */ + /* { dg-regexp "during GIMPLE pass: crash_test" } */ +} + +/* 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 "\"artifacts\": \\\[" } } + { dg-final { scan-sarif-file "\"location\": " } } + { dg-final { scan-sarif-file "\"uri\": " } } + + { dg-final { scan-sarif-file "\"sourceLanguage\": \"c\"" { target c } } } + { dg-final { scan-sarif-file "\"sourceLanguage\": \"cplusplus\"" { target c++ } } } + + { dg-final { scan-sarif-file "\"contents\": " } } + { dg-final { scan-sarif-file "\"text\": " } } + { 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 "\"fullName\": \"GNU C" } } + { dg-final { scan-sarif-file "\"informationUri\": \"" } } + { dg-final { scan-sarif-file "\"extensions\": \\\[" } } + { dg-final { scan-sarif-file "\"name\": \"crash_test_plugin\"" } } + + We expect no results: + { dg-final { scan-sarif-file "\"results\": \\\[\\\]" } } + + but instead should have an invocations array... + + { dg-final { scan-sarif-file "\"invocations\": \\\[" } } + + ...containing this: + { dg-final { scan-sarif-file "\"executionSuccessful\": false" } } + { dg-final { scan-sarif-file "\"toolExecutionNotifications\": \\\[" } } + + ...containing this notification: + { dg-final { scan-sarif-file "\"level\": \"error\"" } } + { dg-final { scan-sarif-file "\"locations\": \\\[" } } + { dg-final { scan-sarif-file "\"logicalLocations\": \\\[" } } + { dg-final { scan-sarif-file "\"kind\": \"function\"" } } + { dg-final { scan-sarif-file "\"name\": \"test_inject_ice\"" } } + { dg-final { scan-sarif-file "\"physicalLocation\": " } } + { dg-final { scan-sarif-file "\"contextRegion\": " } } + { dg-final { scan-sarif-file "\"artifactLocation\": " } } + { dg-final { scan-sarif-file "\"region\": " } } + { dg-final { scan-sarif-file "\"startLine\": 8" } } + { dg-final { scan-sarif-file "\"startColumn\": 3" } } + { dg-final { scan-sarif-file "\"endColumn\": 16" } } + { dg-final { scan-sarif-file "\"message\": " } } + { dg-final { scan-sarif-file "\"text\": \"I'm sorry Dave, I'm afraid I can't do that\"" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/crash-test-ice-stderr.c b/gcc/testsuite/gcc.dg/plugin/crash-test-ice-stderr.c new file mode 100644 index 00000000000..cee701b135c --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/crash-test-ice-stderr.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +extern void inject_ice (void); + +void test_1 (void) +{ + inject_ice (); /* { dg-ice "I'm sorry Dave, I'm afraid I can't do that" } */ + /* { dg-regexp "during GIMPLE pass: crash_test" } */ +} diff --git a/gcc/testsuite/gcc.dg/plugin/crash-test-write-though-null-sarif.c b/gcc/testsuite/gcc.dg/plugin/crash-test-write-though-null-sarif.c new file mode 100644 index 00000000000..99de3f888d4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/crash-test-write-though-null-sarif.c @@ -0,0 +1,62 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=sarif-file" } */ + +extern void inject_write_through_null (void); + +void test_inject_write_through_null (void) +{ + inject_write_through_null (); /* { dg-ice "" } */ + /* { dg-regexp "during GIMPLE pass: crash_test" } */ +} + +/* 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 "\"artifacts\": \\\[" } } + { dg-final { scan-sarif-file "\"location\": " } } + { dg-final { scan-sarif-file "\"uri\": " } } + + { dg-final { scan-sarif-file "\"sourceLanguage\": \"c\"" { target c } } } + { dg-final { scan-sarif-file "\"sourceLanguage\": \"cplusplus\"" { target c++ } } } + + { dg-final { scan-sarif-file "\"contents\": " } } + { dg-final { scan-sarif-file "\"text\": " } } + { 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 "\"fullName\": \"GNU C" } } + { dg-final { scan-sarif-file "\"informationUri\": \"" } } + { dg-final { scan-sarif-file "\"extensions\": \\\[" } } + { dg-final { scan-sarif-file "\"name\": \"crash_test_plugin\"" } } + + We expect no results: + { dg-final { scan-sarif-file "\"results\": \\\[\\\]" } } + + but instead should have an invocations array... + + { dg-final { scan-sarif-file "\"invocations\": \\\[" } } + + ...containing this: + { dg-final { scan-sarif-file "\"executionSuccessful\": false" } } + { dg-final { scan-sarif-file "\"toolExecutionNotifications\": \\\[" } } + + ...containing this notification: + { dg-final { scan-sarif-file "\"level\": \"error\"" } } + { dg-final { scan-sarif-file "\"locations\": \\\[" } } + { dg-final { scan-sarif-file "\"logicalLocations\": \\\[" } } + { dg-final { scan-sarif-file "\"kind\": \"function\"" } } + { dg-final { scan-sarif-file "\"name\": \"test_inject_write_through_null\"" } } + { dg-final { scan-sarif-file "\"physicalLocation\": " } } + { dg-final { scan-sarif-file "\"contextRegion\": " } } + { dg-final { scan-sarif-file "\"artifactLocation\": " } } + { dg-final { scan-sarif-file "\"region\": " } } + { dg-final { scan-sarif-file "\"startLine\": 8" } } + { dg-final { scan-sarif-file "\"startColumn\": 3" } } + { dg-final { scan-sarif-file "\"endColumn\": 31" } } + { dg-final { scan-sarif-file "\"message\": " } } + { dg-final { scan-sarif-file "\"text\": \"Segmentation fault\"" } } */ diff --git a/gcc/testsuite/gcc.dg/plugin/crash-test-write-though-null-stderr.c b/gcc/testsuite/gcc.dg/plugin/crash-test-write-though-null-stderr.c new file mode 100644 index 00000000000..7b43e423633 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/crash-test-write-though-null-stderr.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +extern void inject_write_through_null (void); + +void test_inject_write_through_null (void) +{ + inject_write_through_null (); /* { dg-ice "Segmentation fault" } */ + /* { dg-regexp "during GIMPLE pass: crash_test" } */ +} diff --git a/gcc/testsuite/gcc.dg/plugin/crash_test_plugin.c b/gcc/testsuite/gcc.dg/plugin/crash_test_plugin.c new file mode 100644 index 00000000000..03ad096964b --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/crash_test_plugin.c @@ -0,0 +1,135 @@ +/* { dg-options "-O" } */ + +#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.h" +#include "gimple-iterator.h" +#include "gimple-fold.h" +#include "tree-eh.h" +#include "gimple-expr.h" +#include "is-a.h" +#include "tree.h" +#include "tree-pass.h" +#include "intl.h" +#include "plugin-version.h" +#include "c-family/c-common.h" +#include "diagnostic.h" +#include "context.h" + +int plugin_is_GPL_compatible; + +/* A custom pass for injecting a crash in the middle-end when compiling + certain functions. */ + +const pass_data pass_data_crash_test = +{ + GIMPLE_PASS, /* type */ + "crash_test", /* 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_crash_test : public gimple_opt_pass +{ +public: + pass_crash_test(gcc::context *ctxt) + : gimple_opt_pass(pass_data_crash_test, ctxt) + {} + + /* opt_pass methods: */ + bool gate (function *) final override { return true; } + unsigned int execute (function *) final override; + +}; // class pass_test_groups + +/* Determine if STMT is a call 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) +{ + gcc_assert (funcname); + + gcall *call = dyn_cast (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; + + return call; +} + +unsigned int +pass_crash_test::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); + if (gcall *call = check_for_named_call (stmt, "inject_ice")) + { + input_location = stmt->location; + internal_error ("I'm sorry Dave, I'm afraid I can't do that"); + } + if (gcall *call = check_for_named_call (stmt, + "inject_write_through_null")) + { + input_location = stmt->location; + int *p = NULL; + *p = 42; + } + } + + return 0; +} + +/* Entrypoint for the plugin. + Create and register the custom pass. */ + +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_crash_test (g); + pass_info.reference_pass_name = "*warn_function_noreturn"; + 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; +} diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp index 7038a7152ac..4d6304cd100 100644 --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp @@ -69,6 +69,11 @@ set plugin_test_list [list \ { poly-int-05_plugin.c poly-int-test-1.c } \ { poly-int-06_plugin.c poly-int-test-1.c } \ { poly-int-07_plugin.c poly-int-test-1.c } \ + { crash_test_plugin.c \ + crash-test-ice-stderr.c \ + crash-test-write-though-null-stderr.c \ + crash-test-ice-sarif.c \ + crash-test-write-though-null-sarif.c } \ { diagnostic_group_plugin.c \ diagnostic-group-test-1.c } \ { diagnostic_plugin_test_show_locus.c \