PR jit/63969: Fix segfault in error-handling when driver isn't found
authorDavid Malcolm <dmalcolm@redhat.com>
Mon, 1 Dec 2014 15:58:11 +0000 (15:58 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Mon, 1 Dec 2014 15:58:11 +0000 (15:58 +0000)
gcc/jit/ChangeLog:
PR jit/63969
* jit-playback.c: Ensure that ctxt_progname is non-NULL.

gcc/testsuite/ChangeLog:
PR jit/63969
* jit.dg/harness.h (CHECK_STRING_STARTS_WITH): New.
(check_string_starts_with): New.
* jit.dg/test-error-pr63969-missing-driver.c: New.

From-SVN: r218226

gcc/jit/ChangeLog
gcc/jit/jit-playback.c
gcc/testsuite/ChangeLog
gcc/testsuite/jit.dg/harness.h
gcc/testsuite/jit.dg/test-error-pr63969-missing-driver.c [new file with mode: 0644]

index f0136b4d98b4abd2dbb151bef1f9a795f0ec0665..9555e729dd7988199f92040ea537aee594583c2f 100644 (file)
@@ -1,3 +1,8 @@
+2014-12-01  David Malcolm  <dmalcolm@redhat.com>
+
+       PR jit/63969
+       * jit-playback.c: Ensure that ctxt_progname is non-NULL.
+
 2014-11-19  David Malcolm  <dmalcolm@redhat.com>
 
        PR jit/63854
index 8fdfa29b0a0f55e2a4e76ddd338b26e61ccdc749..584a8e63759c0a956e0a2e81c1631f2202f77b5f 100644 (file)
@@ -1571,9 +1571,11 @@ compile ()
   /* Pass in user-provided program name as argv0, if any, so that it
      makes it into GCC's "progname" global, used in various diagnostics. */
   ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
-  fake_args[0] =
-    (ctxt_progname ? ctxt_progname : "libgccjit.so");
 
+  if (!ctxt_progname)
+    ctxt_progname = "libgccjit.so";
+
+  fake_args[0] = ctxt_progname;
   fake_args[1] = m_path_c_file;
   num_args = 2;
 
@@ -1689,6 +1691,9 @@ compile ()
     /* pex argv arrays are NULL-terminated.  */
     argv[6] = NULL;
 
+    /* pex_one's error-handling requires pname to be non-NULL.  */
+    gcc_assert (ctxt_progname);
+
     errmsg = pex_one (PEX_SEARCH, /* int flags, */
                      gcc_driver_name,
                      const_cast<char * const *> (argv),
index 94ca3b6292f9b4d1337344243f008b2fdf42b580..d86e406ef3f86c64ec8e868e36c5ae26209ee7b3 100644 (file)
@@ -1,3 +1,10 @@
+2014-12-01  David Malcolm  <dmalcolm@redhat.com>
+
+       PR jit/63969
+       * jit.dg/harness.h (CHECK_STRING_STARTS_WITH): New.
+       (check_string_starts_with): New.
+       * jit.dg/test-error-pr63969-missing-driver.c: New.
+
 2014-12-01  David Malcolm  <dmalcolm@redhat.com>
 
        * jit.dg/jit.exp (jit-dg-test): Use $name rathen than $prog
index f326891c56defab481fa38412bdf5250b5361427..bff64de020140d491b608ef0ebd25c95d9de5ef2 100644 (file)
@@ -81,6 +81,9 @@ static char test[1024];
 #define CHECK_STRING_VALUE(ACTUAL, EXPECTED) \
   check_string_value ((ACTUAL), (EXPECTED));
 
+#define CHECK_STRING_STARTS_WITH(ACTUAL, EXPECTED_PREFIX) \
+  check_string_starts_with ((ACTUAL), (EXPECTED_PREFIX));
+
 #define CHECK(COND) \
   do {                                 \
     if (COND)                          \
@@ -103,6 +106,10 @@ verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
 
 extern void check_string_value (const char *actual, const char *expected);
 
+extern void
+check_string_starts_with (const char *actual,
+                         const char *expected_prefix);
+
 /* Implement framework needed for turning the testcase hooks into an
    executable.  test-combination.c and test-threads.c each combine multiple
    testcases into larger testcases, so we have COMBINED_TEST as a way of
@@ -137,6 +144,30 @@ void check_string_value (const char *actual, const char *expected)
       pass ("%s: actual: NULL == expected: NULL");
 }
 
+void
+check_string_starts_with (const char *actual,
+                         const char *expected_prefix)
+{
+  if (!actual)
+    {
+      fail ("%s: actual: NULL != expected prefix: \"%s\"",
+           test, expected_prefix);
+      fprintf (stderr, "incorrect value\n");
+      abort ();
+    }
+
+  if (strncmp (actual, expected_prefix, strlen (expected_prefix)))
+    {
+      fail ("%s: actual: \"%s\" did not begin with expected prefix: \"%s\"",
+           test, actual, expected_prefix);
+      fprintf (stderr, "incorrect value\n");
+      abort ();
+    }
+
+  pass ("%s: actual: \"%s\" begins with expected prefix: \"%s\"",
+       test, actual, expected_prefix);
+}
+
 static void set_options (gcc_jit_context *ctxt, const char *argv0)
 {
   /* Set up options.  */
diff --git a/gcc/testsuite/jit.dg/test-error-pr63969-missing-driver.c b/gcc/testsuite/jit.dg/test-error-pr63969-missing-driver.c
new file mode 100644 (file)
index 0000000..13f5e3b
--- /dev/null
@@ -0,0 +1,38 @@
+/* PR jit/63969: libgccjit would segfault inside gcc_jit_context_compile
+   if the driver wasn't found on PATH if GCC_JIT_STR_OPTION_PROGNAME was
+   NULL.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Create nothing within the context.  */
+
+  /* harness.h's set_options has set a sane value for
+     GCC_JIT_STR_OPTION_PROGNAME, but PR jit/63969 only segfaulted if it's
+     NULL.
+
+     Unset it.  */
+  gcc_jit_context_set_str_option (ctxt, GCC_JIT_STR_OPTION_PROGNAME, NULL);
+
+  /* Break PATH, so that the driver can't be found
+     by gcc::jit::playback::context::compile ()
+     within gcc_jit_context_compile.  */
+  unsetenv ("PATH");
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that a sane error message was emitted.  */
+  CHECK_STRING_STARTS_WITH (gcc_jit_context_get_first_error (ctxt),
+                           "error invoking gcc driver");
+}