Commit 199501ea by David Malcolm Committed by David Malcolm

PR jit/69144: Ensure that libgccjit's tempdir is fully cleaned-up

There were a couple of ways that libgccjit could fail to unlink all
of its tempfiles, leading to /tmp/libgccjit-* tempdirs lingering
after the build:
- dumpfiles requested by gcc_jit_context_enable_dump
- ahead-of-time compilation artifacts which lingered in the tempdir
  after they've been copied up to the output_path.  This was only
  the case for GCC_JIT_OUTPUT_KIND_OBJECT_FILE and
  GCC_JIT_OUTPUT_KIND_EXECUTABLE.

The following patch fixes these by introducing a vec of additional
cleanups to be performed by gcc:jit::tempdir's dtor.

In addition, if a gcc_jit_result * is leaked and
GCC_JIT_BOOL_OPTION_DEBUGINFO is enabled, the tempdir will also
not be cleaned up.  This was the case for tut04-toyvm/toyvm.cc
which the patch fixes by introducing a wrapper around
gcc_jit_result *.  Doing this required some updates to the
corresponding docs.

gcc/jit/ChangeLog:
	PR jit/69144
	* jit-playback.c (gcc::jit::playback::compile_to_file::postprocess):
	Potentially add the temporary artifact to the tempdir's list of
	tempfiles needing additional cleanup.
	(gcc::jit::playback::context::extract_any_requested_dumps): Likewise
	for the dumpfile.
	* jit-tempdir.c (gcc::jit::tempdir::~tempdir): Clean up additional
	tempfiles.
	* jit-tempdir.h (gcc::jit::tempdir::add_temp_file): New method.
	(gcc::jit::tempdir::m_tempfiles): New field.
	* docs/cp/intro/tutorial04.rst: Update for changes to toyvm.cc.
	* docs/examples/tut04-toyvm/toyvm.cc (class compilation_result):
	New.
	(toyvm_function::compile): Change return type from function ptr
	to a compilation_result.
	(toyvm_function::get_function_name): New accessor.
	(toyvm_function::m_funcname): New field.
	(get_function_name): Convert to...
	(toyvm_function::make_function_name): ...this new method.
	(toyvm_function::parse): Call make_function_name.
	(toyvm_function::compile): Convert return type from function ptr
	to a compilation_result.  Use get_function_name.
	(compilation_state::compile): Convert return type from
	gcc_jit_result * to a compilation_result.
	(test_script): Update for above changes, extracting the code from
	the compilation_result.
	(main): Likewise.
	* docs/_build/texinfo/libgccjit.texi: Regenerate.

From-SVN: r232582
parent f57fc960
2016-01-19 David Malcolm <dmalcolm@redhat.com>
PR jit/69144
* jit-playback.c (gcc::jit::playback::compile_to_file::postprocess):
Potentially add the temporary artifact to the tempdir's list of
tempfiles needing additional cleanup.
(gcc::jit::playback::context::extract_any_requested_dumps): Likewise
for the dumpfile.
* jit-tempdir.c (gcc::jit::tempdir::~tempdir): Clean up additional
tempfiles.
* jit-tempdir.h (gcc::jit::tempdir::add_temp_file): New method.
(gcc::jit::tempdir::m_tempfiles): New field.
* docs/cp/intro/tutorial04.rst: Update for changes to toyvm.cc.
* docs/examples/tut04-toyvm/toyvm.cc (class compilation_result):
New.
(toyvm_function::compile): Change return type from function ptr
to a compilation_result.
(toyvm_function::get_function_name): New accessor.
(toyvm_function::m_funcname): New field.
(get_function_name): Convert to...
(toyvm_function::make_function_name): ...this new method.
(toyvm_function::parse): Call make_function_name.
(toyvm_function::compile): Convert return type from function ptr
to a compilation_result. Use get_function_name.
(compilation_state::compile): Convert return type from
gcc_jit_result * to a compilation_result.
(test_script): Update for above changes, extracting the code from
the compilation_result.
(main): Likewise.
* docs/_build/texinfo/libgccjit.texi: Regenerate.
2016-01-04 Jakub Jelinek <jakub@redhat.com> 2016-01-04 Jakub Jelinek <jakub@redhat.com>
Update copyright years. Update copyright years.
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -297,15 +297,14 @@ Compiling the context ...@@ -297,15 +297,14 @@ Compiling the context
Having finished looping over the blocks and populating them with Having finished looping over the blocks and populating them with
statements, the context is complete. statements, the context is complete.
We can now compile it, and extract machine code from the result: We can now compile it, extract machine code from the result, and
run it:
.. literalinclude:: ../../examples/tut04-toyvm/toyvm.cc .. literalinclude:: ../../examples/tut04-toyvm/toyvm.cc
:start-after: /* We've now finished populating the context. Compile it. */ :start-after: /* Wrapper around a gcc_jit_result *. */
:end-before: /* (this leaks "result" and "funcname") */ :end-before: /* Functions are compiled to this function ptr type. */
:language: c++ :language: c++
We can now run the result:
.. literalinclude:: ../../examples/tut04-toyvm/toyvm.cc .. literalinclude:: ../../examples/tut04-toyvm/toyvm.cc
:start-after: /* JIT-compilation. */ :start-after: /* JIT-compilation. */
:end-before: return 0; :end-before: return 0;
......
...@@ -28,6 +28,29 @@ along with GCC; see the file COPYING3. If not see ...@@ -28,6 +28,29 @@ along with GCC; see the file COPYING3. If not see
#include <libgccjit++.h> #include <libgccjit++.h>
/* Wrapper around a gcc_jit_result *. */
class compilation_result
{
public:
compilation_result (gcc_jit_result *result) :
m_result (result)
{
}
~compilation_result ()
{
gcc_jit_result_release (m_result);
}
void *get_code (const char *funcname)
{
return gcc_jit_result_get_code (m_result, funcname);
}
private:
gcc_jit_result *m_result;
};
/* Functions are compiled to this function ptr type. */ /* Functions are compiled to this function ptr type. */
typedef int (*toyvm_compiled_func) (int); typedef int (*toyvm_compiled_func) (int);
...@@ -100,11 +123,19 @@ public: ...@@ -100,11 +123,19 @@ public:
int int
interpret (int arg, FILE *trace); interpret (int arg, FILE *trace);
toyvm_compiled_func compilation_result
compile (); compile ();
const char *
get_function_name () const { return m_funcname; }
private:
void
make_function_name (const char *filename);
private: private:
const char *fn_filename; const char *fn_filename;
char *m_funcname;
int fn_num_ops; int fn_num_ops;
toyvm_op fn_ops[MAX_OPS]; toyvm_op fn_ops[MAX_OPS];
friend struct compilation_state; friend struct compilation_state;
...@@ -149,8 +180,8 @@ toyvm_function::add_unary_op (enum opcode opcode, ...@@ -149,8 +180,8 @@ toyvm_function::add_unary_op (enum opcode opcode,
add_op (opcode, operand, linenum); add_op (opcode, operand, linenum);
} }
static char * void
get_function_name (const char *filename) toyvm_function::make_function_name (const char *filename)
{ {
/* Skip any path separators. */ /* Skip any path separators. */
const char *pathsep = strrchr (filename, '/'); const char *pathsep = strrchr (filename, '/');
...@@ -158,14 +189,12 @@ get_function_name (const char *filename) ...@@ -158,14 +189,12 @@ get_function_name (const char *filename)
filename = pathsep + 1; filename = pathsep + 1;
/* Copy filename to funcname. */ /* Copy filename to funcname. */
char *funcname = (char *)malloc (strlen (filename) + 1); m_funcname = (char *)malloc (strlen (filename) + 1);
strcpy (funcname, filename); strcpy (m_funcname, filename);
/* Convert "." to NIL terminator. */ /* Convert "." to NIL terminator. */
*(strchr (funcname, '.')) = '\0'; *(strchr (m_funcname, '.')) = '\0';
return funcname;
} }
toyvm_function * toyvm_function *
...@@ -197,6 +226,7 @@ toyvm_function::parse (const char *filename, const char *name) ...@@ -197,6 +226,7 @@ toyvm_function::parse (const char *filename, const char *name)
goto error; goto error;
} }
fn->fn_filename = filename; fn->fn_filename = filename;
fn->make_function_name (filename);
/* Read the lines of the file. */ /* Read the lines of the file. */
while ((linelen = getline (&line, &bufsize, f)) != -1) while ((linelen = getline (&line, &bufsize, f)) != -1)
...@@ -420,7 +450,7 @@ public: ...@@ -420,7 +450,7 @@ public:
void create_types (); void create_types ();
void create_locations (); void create_locations ();
void create_function (const char *funcname); void create_function (const char *funcname);
gcc_jit_result *compile (); compilation_result compile ();
private: private:
void void
...@@ -462,24 +492,18 @@ private: ...@@ -462,24 +492,18 @@ private:
/* The main compilation hook. */ /* The main compilation hook. */
toyvm_compiled_func compilation_result
toyvm_function::compile () toyvm_function::compile ()
{ {
compilation_state state (*this); compilation_state state (*this);
char *funcname;
funcname = get_function_name (fn_filename);
state.create_context (); state.create_context ();
state.create_types (); state.create_types ();
state.create_locations (); state.create_locations ();
state.create_function (funcname); state.create_function (get_function_name ());
/* We've now finished populating the context. Compile it. */ /* We've now finished populating the context. Compile it. */
gcc_jit_result *result = state.compile (); return state.compile ();
return (toyvm_compiled_func)gcc_jit_result_get_code (result, funcname);
/* (this leaks "result" and "funcname") */
} }
/* Stack manipulation. */ /* Stack manipulation. */
...@@ -767,7 +791,7 @@ compilation_state::create_function (const char *funcname) ...@@ -767,7 +791,7 @@ compilation_state::create_function (const char *funcname)
} /* end of loop on PC locations. */ } /* end of loop on PC locations. */
} }
gcc_jit_result * compilation_result
compilation_state::compile () compilation_state::compile ()
{ {
return ctxt.compile (); return ctxt.compile ();
...@@ -825,7 +849,10 @@ test_script (const char *scripts_dir, const char *script_name, int input, ...@@ -825,7 +849,10 @@ test_script (const char *scripts_dir, const char *script_name, int input,
interpreted_result = fn->interpret (input, NULL); interpreted_result = fn->interpret (input, NULL);
CHECK_VALUE (interpreted_result, expected_result); CHECK_VALUE (interpreted_result, expected_result);
code = fn->compile (); compilation_result compiler_result = fn->compile ();
const char *funcname = fn->get_function_name ();
code = (toyvm_compiled_func)compiler_result.get_code (funcname);
CHECK_NON_NULL (code); CHECK_NON_NULL (code);
compiled_result = code (input); compiled_result = code (input);
...@@ -894,7 +921,12 @@ main (int argc, char **argv) ...@@ -894,7 +921,12 @@ main (int argc, char **argv)
fn->interpret (atoi (argv[2]), NULL)); fn->interpret (atoi (argv[2]), NULL));
/* JIT-compilation. */ /* JIT-compilation. */
toyvm_compiled_func code = fn->compile (); compilation_result compiler_result = fn->compile ();
const char *funcname = fn->get_function_name ();
toyvm_compiled_func code
= (toyvm_compiled_func)compiler_result.get_code (funcname);
printf ("compiler result: %d\n", printf ("compiler result: %d\n",
code (atoi (argv[2]))); code (atoi (argv[2])));
......
...@@ -1888,6 +1888,7 @@ playback::compile_to_file::postprocess (const char *ctxt_progname) ...@@ -1888,6 +1888,7 @@ playback::compile_to_file::postprocess (const char *ctxt_progname)
case GCC_JIT_OUTPUT_KIND_ASSEMBLER: case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
copy_file (get_tempdir ()->get_path_s_file (), copy_file (get_tempdir ()->get_path_s_file (),
m_output_path); m_output_path);
/* The .s file is automatically unlinked by tempdir::~tempdir. */
break; break;
case GCC_JIT_OUTPUT_KIND_OBJECT_FILE: case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
...@@ -1902,9 +1903,13 @@ playback::compile_to_file::postprocess (const char *ctxt_progname) ...@@ -1902,9 +1903,13 @@ playback::compile_to_file::postprocess (const char *ctxt_progname)
false, /* bool shared, */ false, /* bool shared, */
false);/* bool run_linker */ false);/* bool run_linker */
if (!errors_occurred ()) if (!errors_occurred ())
copy_file (tmp_o_path, {
m_output_path); copy_file (tmp_o_path,
free (tmp_o_path); m_output_path);
get_tempdir ()->add_temp_file (tmp_o_path);
}
else
free (tmp_o_path);
} }
break; break;
...@@ -1918,6 +1923,7 @@ playback::compile_to_file::postprocess (const char *ctxt_progname) ...@@ -1918,6 +1923,7 @@ playback::compile_to_file::postprocess (const char *ctxt_progname)
if (!errors_occurred ()) if (!errors_occurred ())
copy_file (get_tempdir ()->get_path_so_file (), copy_file (get_tempdir ()->get_path_so_file (),
m_output_path); m_output_path);
/* The .so file is automatically unlinked by tempdir::~tempdir. */
break; break;
case GCC_JIT_OUTPUT_KIND_EXECUTABLE: case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
...@@ -1932,9 +1938,13 @@ playback::compile_to_file::postprocess (const char *ctxt_progname) ...@@ -1932,9 +1938,13 @@ playback::compile_to_file::postprocess (const char *ctxt_progname)
false, /* bool shared, */ false, /* bool shared, */
true);/* bool run_linker */ true);/* bool run_linker */
if (!errors_occurred ()) if (!errors_occurred ())
copy_file (tmp_exe_path, {
m_output_path); copy_file (tmp_exe_path,
free (tmp_exe_path); m_output_path);
get_tempdir ()->add_temp_file (tmp_exe_path);
}
else
free (tmp_exe_path);
} }
break; break;
...@@ -2279,7 +2289,7 @@ extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps) ...@@ -2279,7 +2289,7 @@ extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
filename = g->get_dumps ()->get_dump_file_name (dfi); filename = g->get_dumps ()->get_dump_file_name (dfi);
content = read_dump_file (filename); content = read_dump_file (filename);
*(d->m_out_ptr) = content; *(d->m_out_ptr) = content;
free (filename); m_tempdir->add_temp_file (filename);
} }
} }
......
...@@ -121,7 +121,7 @@ gcc::jit::tempdir::~tempdir () ...@@ -121,7 +121,7 @@ gcc::jit::tempdir::~tempdir ()
fprintf (stderr, "intermediate files written to %s\n", m_path_tempdir); fprintf (stderr, "intermediate files written to %s\n", m_path_tempdir);
else else
{ {
/* Clean up .s/.so and tempdir. */ /* Clean up .s/.so. */
if (m_path_s_file) if (m_path_s_file)
{ {
log ("unlinking .s file: %s", m_path_s_file); log ("unlinking .s file: %s", m_path_s_file);
...@@ -132,6 +132,17 @@ gcc::jit::tempdir::~tempdir () ...@@ -132,6 +132,17 @@ gcc::jit::tempdir::~tempdir ()
log ("unlinking .so file: %s", m_path_so_file); log ("unlinking .so file: %s", m_path_so_file);
unlink (m_path_so_file); unlink (m_path_so_file);
} }
/* Clean up any other tempfiles. */
int i;
char *tempfile;
FOR_EACH_VEC_ELT (m_tempfiles, i, tempfile)
{
log ("unlinking tempfile: %s", tempfile);
unlink (tempfile);
}
/* The tempdir should now be empty; remove it. */
if (m_path_tempdir) if (m_path_tempdir)
{ {
log ("removing tempdir: %s", m_path_tempdir); log ("removing tempdir: %s", m_path_tempdir);
...@@ -145,4 +156,9 @@ gcc::jit::tempdir::~tempdir () ...@@ -145,4 +156,9 @@ gcc::jit::tempdir::~tempdir ()
free (m_path_c_file); free (m_path_c_file);
free (m_path_s_file); free (m_path_s_file);
free (m_path_so_file); free (m_path_so_file);
int i;
char *tempfile;
FOR_EACH_VEC_ELT (m_tempfiles, i, tempfile)
free (tempfile);
} }
...@@ -58,6 +58,10 @@ class tempdir : public log_user ...@@ -58,6 +58,10 @@ class tempdir : public log_user
const char * get_path_s_file () const { return m_path_s_file; } const char * get_path_s_file () const { return m_path_s_file; }
const char * get_path_so_file () const { return m_path_so_file; } const char * get_path_so_file () const { return m_path_so_file; }
/* Add PATH to the vec of tempfiles that must be unlinked.
Take ownership of the buffer PATH; it will be freed. */
void add_temp_file (char *path) { m_tempfiles.safe_push (path); }
private: private:
/* Was GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES set? If so, keep the /* Was GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES set? If so, keep the
on-disk tempdir around after this wrapper object goes away. */ on-disk tempdir around after this wrapper object goes away. */
...@@ -74,6 +78,10 @@ class tempdir : public log_user ...@@ -74,6 +78,10 @@ class tempdir : public log_user
char *m_path_s_file; char *m_path_s_file;
char *m_path_so_file; char *m_path_so_file;
/* Other files within the tempdir to be cleaned up:
- certain ahead-of-time compilation artifacts (.o and .exe files)
- dumpfiles that were requested via gcc_jit_context_enable_dump. */
auto_vec <char *> m_tempfiles;
}; };
} // namespace gcc::jit } // namespace gcc::jit
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment