fix: redirect

@cipher1024 I modified your fix. It would produce memory leaks if the
code executed by #eval modifies the stdout.
Here is the problem.
- Your replaces the handler with some new handler `H` and stores the
  old handler `O` in a `flet`.
- Code is executed and replaces the stdout handler with `H'`. The `H`s RC is
  decremented and `H'`s RC is incremeneted. So far, so good.
- Now, the destructor of your `flet` is executed, and it replaces `H'`
  with `O`, but `H'` RC is not decremented.
This commit is contained in:
Leonardo de Moura 2020-01-23 15:58:34 -08:00
parent 123577126c
commit addbb8dd67
2 changed files with 17 additions and 6 deletions

View file

@ -336,10 +336,20 @@ struct stream_buffer_delete {
}
};
flet<object *> lean_redirect_stdout(object * new_stdout);
obj_res lean_redirect_stdout(obj_arg new_stdout);
lean_object * lean_io_wrap_handle(FILE *hfile);
lean_object *& get_handle_current_stdout();
struct redirect_helper {
object_ref m_old_fp;
redirect_helper(object_ref const & new_fp):
m_old_fp(lean_redirect_stdout(new_fp.to_obj_arg())) {
}
~redirect_helper() {
lean_dec(lean_redirect_stdout(m_old_fp.to_obj_arg()));
}
};
static environment eval_cmd(parser & p) {
transient_cmd_scope cmd_scope(p);
auto pos = p.pos();
@ -399,8 +409,8 @@ static environment eval_cmd(parser & p) {
object_ref r;
try {
object_ref newFP(lean_io_wrap_handle(fp));
flet<object *> oldFP(lean_redirect_stdout(newFP.raw()));
object_ref new_fp(lean_io_wrap_handle(fp));
redirect_helper helper(new_fp);
if (p.profiling()) {
timeit timer(out.get_text_stream().get_stream(), "eval time");
r = object_ref(ir::run_boxed(new_env, fn_name, args.size(), &args[0]));

View file

@ -22,7 +22,6 @@ Author: Leonardo de Moura
#include <cctype>
#include <sys/stat.h>
#include "util/io.h"
#include "runtime/flet.h"
#include "runtime/utf8.h"
#include "runtime/object.h"
#include "runtime/thread.h"
@ -145,8 +144,10 @@ MK_THREAD_LOCAL_GET(object *, get_handle_current_stdout, g_handle_stdout);
MK_THREAD_LOCAL_GET(object *, get_handle_current_stderr, g_handle_stderr);
MK_THREAD_LOCAL_GET(object *, get_handle_current_stdin, g_handle_stdin);
flet<object *> lean_redirect_stdout(object * new_stdout) {
return flet<object *>(get_handle_current_stdout(), new_stdout);
obj_res lean_redirect_stdout(obj_arg new_stdout) {
obj_res r = get_handle_current_stdout();
get_handle_current_stdout() = new_stdout;
return r;
}
/* getStdout : IO FS.Handle */