Committed to branch dmalcolm/jit: My libgccjit port of GNU Octave's JIT was segfaulting due to corruption of playback::location values when running Octave's JIT unittests. After lots of debugging, I found that recording::locations in a parent context weren't having their playback::locations cleaned away between compiles, and hence continue to point to a GC-allocated object for which no marking is performed (by design: these objects aren't meant to outlive the compile and hence should always be collected).
Hence we have pointers to supposedly-dead objects that don't get NULLed, and point to bytes that eventually get repurposed by the GC, leading to crashes. The fix is to ensure that when clearing the playback objects from all recording objects we visit those in parent contexts (and above), and not just those in the bottommost context. This bug was elusive, since most recording classes blithely overwrite the old invalid pointers on replay, but recording::location checks for a pre-existing playback::location (since gcc_jit_context_dump_to_file can lead to playback::locations being needed before they would normally be created), and can thus reuse the now-invalid pointer - provided it's in a parent context. We can reproduce this bug by using gcc_jit_context_dump_to_file in test-nested-contexts.c on each context, to set up fake "source locations" on the various entities in each context. Doing so also gives us test coverage of that function. gcc/jit/ * internal-api.c (gcc::jit::recording::context:: disassociate_from_playback): Recursively visit parent contexts. gcc/testsuite/ * jit.dg/test-nested-contexts.c (main): Dump the contexts to files, setting up source locations, and adding test coverage for gcc_jit_context_dump_to_file. --- gcc/jit/ChangeLog.jit | 5 +++++ gcc/jit/internal-api.c | 4 ++++ gcc/testsuite/ChangeLog.jit | 6 ++++++ gcc/testsuite/jit.dg/test-nested-contexts.c | 12 ++++++++++++ 4 files changed, 27 insertions(+) diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit index 3e2799f..b0058b9 100644 --- a/gcc/jit/ChangeLog.jit +++ b/gcc/jit/ChangeLog.jit @@ -1,3 +1,8 @@ +2014-03-06 David Malcolm <dmalc...@redhat.com> + + * internal-api.c (gcc::jit::recording::context:: + disassociate_from_playback): Recursively visit parent contexts. + 2014-03-05 David Malcolm <dmalc...@redhat.com> * libgccjit.h (gcc_jit_function_dump_to_dot): New. diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c index 62301b2..f80c40b 100644 --- a/gcc/jit/internal-api.c +++ b/gcc/jit/internal-api.c @@ -243,6 +243,10 @@ recording::context::disassociate_from_playback () { int i; memento *m; + + if (m_parent_ctxt) + m_parent_ctxt->disassociate_from_playback (); + FOR_EACH_VEC_ELT (m_mementos, i, m) { m->set_playback_obj (NULL); diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit index f66a844..52b606e 100644 --- a/gcc/testsuite/ChangeLog.jit +++ b/gcc/testsuite/ChangeLog.jit @@ -1,3 +1,9 @@ +2014-03-06 David Malcolm <dmalc...@redhat.com> + + * jit.dg/test-nested-contexts.c (main): Dump the contexts to + files, setting up source locations, and adding test coverage for + gcc_jit_context_dump_to_file. + 2014-03-04 David Malcolm <dmalc...@redhat.com> * jit.dg/test-error-mismatching-types-in-call.c: New test case, diff --git a/gcc/testsuite/jit.dg/test-nested-contexts.c b/gcc/testsuite/jit.dg/test-nested-contexts.c index e34d2dd..16bc63f 100644 --- a/gcc/testsuite/jit.dg/test-nested-contexts.c +++ b/gcc/testsuite/jit.dg/test-nested-contexts.c @@ -552,6 +552,10 @@ main (int argc, char **argv) /* No errors should have occurred. */ CHECK_VALUE (gcc_jit_context_get_first_error (top_level.ctxt), NULL); + gcc_jit_context_dump_to_file (top_level.ctxt, + "dump-of-test-nested-contexts-top.c", + 1); + for (j = 1; j <= NUM_MIDDLE_ITERATIONS; j++) { /* Create and populate the middle-level context, using @@ -575,6 +579,10 @@ main (int argc, char **argv) CHECK_VALUE (gcc_jit_context_get_first_error (middle_level.ctxt), NULL); + gcc_jit_context_dump_to_file (middle_level.ctxt, + "dump-of-test-nested-contexts-middle.c", + 1); + gcc_jit_result *middle_result = gcc_jit_context_compile (middle_level.ctxt); CHECK_NON_NULL (middle_result); @@ -607,6 +615,10 @@ main (int argc, char **argv) CHECK_VALUE (gcc_jit_context_get_first_error (bottom_level.ctxt), NULL); + gcc_jit_context_dump_to_file (bottom_level.ctxt, + "dump-of-test-nested-contexts-bottom.c", + 1); + gcc_jit_result *bottom_result = gcc_jit_context_compile (bottom_level.ctxt); verify_bottom_code (bottom_level.ctxt, bottom_result); -- 1.7.11.7