It's not clear to me if I can approve my own patches to the jit, so here's a fix for PR 63969.
Tested via "make check-jit" on Fedora 20 x86_64; testcase segfaults without the fix to jit-playback.c and is fixed with it; all other testcases continue to pass. OK for trunk?
>From 0901383f1a1ad296b939687298b8321446bc54e3 Mon Sep 17 00:00:00 2001 From: David Malcolm <dmalc...@redhat.com> Date: Thu, 20 Nov 2014 01:06:14 -0500 Subject: [PATCH] PR jit/63969: Fix segfault in error-handling when driver isn't found If the driver isn't found on the path, pex_one attempts to print an error message, but if GCC_JIT_STR_OPTION_PROGNAME wasn't set, pex_one's pname was NULL, leading to a segfault. Ensure that pex_one is called with a non-NULL pname, and add a testcase to verify that the user gets a sane error message if the driver isn't on PATH. gcc/jit/ChangeLog: * jit-playback.c: Ensure that ctxt_progname is non-NULL. gcc/testsuite/ChangeLog: * jit.dg/harness.h (CHECK_STRING_STARTS_WITH): New. (check_string_starts_with): New. * jit.dg/test-error-pr63969-missing-driver.c: New. --- gcc/jit/jit-playback.c | 9 +++-- gcc/testsuite/jit.dg/harness.h | 31 ++++++++++++++++++ .../jit.dg/test-error-pr63969-missing-driver.c | 38 ++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/jit.dg/test-error-pr63969-missing-driver.c diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index 8fdfa29..584a8e6 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -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), diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h index f326891..bff64de 100644 --- a/gcc/testsuite/jit.dg/harness.h +++ b/gcc/testsuite/jit.dg/harness.h @@ -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 index 0000000..13f5e3b --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-pr63969-missing-driver.c @@ -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"); +} -- 1.8.5.3