In r227188 I introduced driver::finalize () which resets
all state within gcc.c, allowing the driver code to embedded
inside libgccjit and run repeatedly in-process.

Running this on s390x revealed a bug in this cleanup:
I was cleaning up "specs" via:
                XDELETEVEC (specs);
and this was crashing on s390x with:
  free(): invalid pointer: 0x000003fffdf30568 ***

Closer investigation revealed that specs == static_specs,
a statically allocated array.

What's happening is that set_specs sets "specs" to static_specs
the first time it's called, and any calls to set_specs () with
a name that isn't in static_specs cause a new spec_list node
to be dynamically-allocated and put at the front of the list; "specs"
then equals that.

All of my testing had been on x86_64, which inserts exactly one spec
with a name not in the static array, hence the:
                XDELETEVEC (specs);
happened to work.

On s390x, the only names in the "specs" file are those in the static
array, so specs == static_specs, and the bogus cleanup code attempts
to free a statically-allocated array.

The following patch reworks this part of the cleanup, walking any list
of specs, freeing the dynamically-allocated nodes until the
statically-allocated ones are reached.

driver::finalize is only called by libgccjit, not by the main driver
program, so this should be relatively low-risk.

Verified directly by running under valgrind on x86_64 and s390x.

With the patch, jit.sum on s390x-ibm-linux-gnu (RHEL 7) goes from:
  # of expected passes            1799
  # of unexpected failures        61
  # of unresolved testcases       2
to:
  # of expected passes            8514

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.

OK for trunk?

gcc/ChangeLog:
        PR driver/69779
        * gcc.c (driver::finalize): Fix cleanup of "specs".
---
 gcc/gcc.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/gcc/gcc.c b/gcc/gcc.c
index 683b30f..ba1ee41 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -9898,8 +9898,20 @@ driver::finalize ()
   multilib_os_dir = 0;
   multiarch_dir = 0;
 
-  XDELETEVEC (specs);
-  specs = 0;
+  /* Free any specs dynamically-allocated by set_spec.
+     These will be at the head of the list, before the
+     statically-allocated ones.  */
+  if (specs)
+    {
+      while (specs != static_specs)
+       {
+         spec_list *next = specs->next;
+         free (const_cast <char *> (specs->name));
+         XDELETE (specs);
+         specs = next;
+       }
+      specs = 0;
+    }
   for (unsigned i = 0; i < ARRAY_SIZE (static_specs); i++)
     {
       spec_list *sl = &static_specs[i];
-- 
1.8.5.3

Reply via email to