void
context::set_diagnostic_buffer (buffer *buffer_)
{
+ /* Early reject of no-op (to avoid recursively crashing when handling an
+ ICE when inside a nested diagnostics; see PR diagnostics/121876). */
+ if (buffer_ == m_diagnostic_buffer)
+ return;
+
/* We don't allow changing buffering within a diagnostic group
(to simplify handling of buffered diagnostics within the
diagnostic_format implementations). */
--- /dev/null
+from htmltest import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def html_tree():
+ return html_tree_from_env()
+
+def test_results(html_tree):
+ root = html_tree.getroot ()
+ assert root.tag == make_tag('html')
+
+ head = root.find('xhtml:head', ns)
+ assert head is not None
+
+ body = root.find('xhtml:body', ns)
+ assert body is not None
+
+ diag_list = body.find("./xhtml:div[@class='gcc-diagnostic-list']", ns)
+ assert len(diag_list)
+
+ # Currently the ICE appears nested within the parent error
+ diag = diag_list.find('xhtml:div', ns)
+ assert diag is not None
+ assert diag.attrib['class'] == 'alert alert-danger'
+
+ icon = diag.find('xhtml:span', ns)
+ assert icon.attrib['class'] == 'pficon pficon-error-circle-o'
+
+ # The message line for the parent error:
+ message = diag.find("./xhtml:div[@class='gcc-message']", ns)
+ assert message is not None
+ assert message[0].tag == make_tag('strong')
+ assert message[0].text == 'error: '
+ assert message[0].tail == " placeholder"
+
+ # The ICE
+ ice = diag.find('.//xhtml:div[@class="gcc-diagnostic"]', ns)
+ assert ice is not None
+ ice_msg = ice.find("./xhtml:div[@class='gcc-message']", ns)
+ assert ice_msg is not None
+ assert ice_msg.text == "I'm sorry Dave, I'm afraid I can't do that"
--- /dev/null
+from sarif import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def sarif():
+ return sarif_from_env()
+
+def test_execution_failed(sarif):
+ runs = sarif['runs']
+ run = runs[0]
+
+ invocations = run['invocations']
+ assert len(invocations) == 1
+ invocation = invocations[0]
+
+ assert invocation['executionSuccessful'] == False
+
+def test_notification(sarif):
+ # We expect an execution notification for the ICE in the invocation
+ runs = sarif['runs']
+ run = runs[0]
+
+ invocations = run['invocations']
+ assert len(invocations) == 1
+ invocation = invocations[0]
+
+ assert invocation['executionSuccessful'] == False
+
+ notifications = invocation['toolExecutionNotifications']
+ assert len(notifications) == 1
+
+ notification = notifications[0]
+
+ assert notification['message']['text'] == "I'm sorry Dave, I'm afraid I can't do that"
+ assert notification['level'] == 'error'
+
+ loc0 = notification['locations'][0]
+ assert get_location_artifact_uri(loc0).endswith('crash-test-nested-ice.c')
+ assert 'inject_ice ();' in get_location_snippet_text(loc0)
+
+ # We may have backtrace information
+ if 'properties' in notification:
+ backtrace = notification['properties']['gcc/backtrace']
+ assert 'frames' in backtrace
+ # Ideally we should have a frame for pass_crash_test::execute(function*)
+ # but we can't rely on this.
--- /dev/null
+/* { dg-do compile } */
+/* { dg-additional-options "-fno-report-bug" } */
+/* { dg-additional-options "-fplugin-arg-crash_test_plugin-nested" } */
+/* { dg-additional-options "-fdiagnostics-add-output=sarif" } */
+/* { dg-additional-options "-fdiagnostics-add-output=experimental-html:javascript=no" } */
+
+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-error "placeholder" "" { target *-*-* } .-1 } */
+ /* { dg-regexp "during GIMPLE pass: crash_test" } */
+}
+
+/* Verify that some JSON was written to a file with the expected name. */
+/* { dg-final { verify-sarif-file } } */
+
+/* Use a Python script to verify various properties about the generated
+ .sarif file:
+ { dg-final { run-sarif-pytest crash-test-nested-ice.c "crash-test-nested-ice-sarif.py" } } */
+
+/* Use a Python script to verify various properties about the generated
+ .html file:
+ { dg-final { run-html-pytest crash-test-nested-ice.c "crash-test-nested-ice-html.py" } } */
--- /dev/null
+from htmltest import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def html_tree():
+ return html_tree_from_env()
+
+def test_results(html_tree):
+ root = html_tree.getroot ()
+ assert root.tag == make_tag('html')
+
+ head = root.find('xhtml:head', ns)
+ assert head is not None
+
+ body = root.find('xhtml:body', ns)
+ assert body is not None
+
+ diag_list = body.find("./xhtml:div[@class='gcc-diagnostic-list']", ns)
+ assert len(diag_list)
+
+ # Currently the ICE appears nested within the parent error
+ diag = diag_list.find('xhtml:div', ns)
+ assert diag is not None
+ assert diag.attrib['class'] == 'alert alert-danger'
+
+ icon = diag.find('xhtml:span', ns)
+ assert icon.attrib['class'] == 'pficon pficon-error-circle-o'
+
+ # The message line for the parent error:
+ message = diag.find("./xhtml:div[@class='gcc-message']", ns)
+ assert message is not None
+ assert message[0].tag == make_tag('strong')
+ assert message[0].text == 'error: '
+ assert message[0].tail == " placeholder"
+
+ # The ICE
+ ice = diag.find('.//xhtml:div[@class="gcc-diagnostic"]', ns)
+ assert ice is not None
+ ice_msg = ice.find("./xhtml:div[@class='gcc-message']", ns)
+ assert ice_msg is not None
+ assert ice_msg.text == "Segmentation fault"
--- /dev/null
+from sarif import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def sarif():
+ return sarif_from_env()
+
+def test_execution_failed(sarif):
+ runs = sarif['runs']
+ run = runs[0]
+
+ invocations = run['invocations']
+ assert len(invocations) == 1
+ invocation = invocations[0]
+
+ assert invocation['executionSuccessful'] == False
+
+def test_notification(sarif):
+ # We expect an execution notification for the ICE in the invocation
+ runs = sarif['runs']
+ run = runs[0]
+
+ invocations = run['invocations']
+ assert len(invocations) == 1
+ invocation = invocations[0]
+
+ assert invocation['executionSuccessful'] == False
+
+ notifications = invocation['toolExecutionNotifications']
+ assert len(notifications) == 1
+
+ notification = notifications[0]
+
+ assert notification['message']['text'] == "Segmentation fault"
+ assert notification['level'] == 'error'
+
+ loc0 = notification['locations'][0]
+ assert get_location_artifact_uri(loc0).endswith('crash-test-nested-write-through-null.c')
+ assert 'inject_write_through_null ();' in get_location_snippet_text(loc0)
+
+ # We may have backtrace information
+ if 'properties' in notification:
+ backtrace = notification['properties']['gcc/backtrace']
+ assert 'frames' in backtrace
+ # Ideally we should have a frame for pass_crash_test::execute(function*)
+ # but we can't rely on this.
--- /dev/null
+/* { dg-do compile } */
+/* { dg-additional-options "-fno-report-bug" } */
+/* { dg-additional-options "-fplugin-arg-crash_test_plugin-nested" } */
+/* { dg-additional-options "-fdiagnostics-add-output=sarif" } */
+/* { dg-additional-options "-fdiagnostics-add-output=experimental-html:javascript=no" } */
+
+extern void inject_write_through_null (void);
+
+void test_inject_write_through_null (void)
+{
+ inject_write_through_null (); /* { dg-ice "Segmentation fault" } */
+ /* { dg-error "placeholder" "" { target *-*-* } .-1 } */
+ /* { dg-regexp "during GIMPLE pass: crash_test" } */
+}
+
+/* Verify that some JSON was written to a file with the expected name. */
+/* { dg-final { verify-sarif-file } } */
+
+/* Use a Python script to verify various properties about the generated
+ .sarif file:
+ { dg-final { run-sarif-pytest crash-test-nested-write-through-null.c "crash-test-nested-write-through-null-sarif.py" } } */
+
+/* Use a Python script to verify various properties about the generated
+ .html file:
+ { dg-final { run-html-pytest crash-test-nested-write-through-null.c "crash-test-nested-write-through-null-html.py" } } */
class pass_crash_test : public gimple_opt_pass
{
public:
- pass_crash_test(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_crash_test, ctxt)
+ pass_crash_test (gcc::context *ctxt, bool nested)
+ : gimple_opt_pass (pass_data_crash_test, ctxt),
+ m_nested (nested)
{}
/* opt_pass methods: */
bool gate (function *) final override { return true; }
unsigned int execute (function *) final override;
+private:
+ /* If true, inject the crash whilst within a nested diagnostic
+ (PR diagnostics/121876). */
+ bool m_nested;
+
}; // class pass_test_groups
/* Determine if STMT is a call to a function named FUNCNAME.
gimple *stmt = gsi_stmt (gsi);
if (gcall *call = check_for_named_call (stmt, "inject_ice"))
{
+ auto_diagnostic_group d;
+ if (m_nested)
+ {
+ error_at (stmt->location, "placeholder");
+ global_dc->push_nesting_level ();
+ }
+
input_location = stmt->location;
internal_error ("I'm sorry Dave, I'm afraid I can't do that");
+
+ if (m_nested)
+ {
+ global_dc->pop_nesting_level ();
+ }
}
if (gcall *call = check_for_named_call (stmt,
"inject_write_through_null"))
{
+ auto_diagnostic_group d;
+ if (m_nested)
+ {
+ error_at (stmt->location, "placeholder");
+ global_dc->push_nesting_level ();
+ }
+
input_location = stmt->location;
int *p = NULL;
*p = 42;
+
+ if (m_nested)
+ {
+ global_dc->pop_nesting_level ();
+ }
}
}
if (!plugin_default_version_check (version, &gcc_version))
return 1;
- pass_info.pass = new pass_crash_test (g);
+ bool nested = false;
+
+ for (int i = 0; i < argc; i++)
+ {
+ if (!strcmp (argv[i].key, "nested"))
+ nested = true;
+ }
+
+ pass_info.pass = new pass_crash_test (g, nested);
pass_info.reference_pass_name = "*warn_function_noreturn";
pass_info.ref_pass_instance_number = 1;
pass_info.pos_op = PASS_POS_INSERT_AFTER;
crash-test-ice-in-header-sarif-2.2.c \
crash-test-ice-sarif.c \
crash-test-ice-stderr.c \
+ crash-test-nested-ice.c \
+ crash-test-nested-write-through-null.c \
crash-test-write-through-null-sarif.c \
crash-test-write-through-null-stderr.c } \
{ diagnostic_group_plugin.cc \