diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2009-11-14 10:00:37 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2009-11-14 10:00:37 -0800 |
commit | 9a5d3288441c27c9adef949bdf09161446915dec (patch) | |
tree | 1a3049fdbeb713d6e75688961004bf74647c7d71 /stream.c | |
parent | fe2f8d7123f22cf7755330ac8b289bc3cd838af3 (diff) | |
download | txr-9a5d3288441c27c9adef949bdf09161446915dec.tar.gz txr-9a5d3288441c27c9adef949bdf09161446915dec.tar.bz2 txr-9a5d3288441c27c9adef949bdf09161446915dec.zip |
Fixes for bug 28086. When constructing a cobj, whose associated
C structure contains obj_t * references, we should initialize
that C structure after allocating the cobj. If we initialize
the structure first, it may end up having the /only/ references
to the objects. In that case, the objects are invisible to the
garbage collector. The subsquent allocation of the cobj itself
then may invoke gc which will turn these objects into dust.
The result is a cobj which contains a handle structure that
contains references to free objects. The fix is to allocate
the handle structure, then the cobj which is associated with
that handle, and then initialize the handle, at which point it
is okay if the handle has the only references to some objects.
Care must be taken not to let a cobj escape with a partially
initialized handle structure, and not to trigger gc between
allocating the cobj, and initializing the fields.
Diffstat (limited to 'stream.c')
-rw-r--r-- | stream.c | 12 |
1 files changed, 8 insertions, 4 deletions
@@ -582,14 +582,16 @@ static struct strm_ops dir_ops = { obj_t *make_stdio_stream(FILE *f, obj_t *descr, obj_t *input, obj_t *output) { struct stdio_handle *h = (struct stdio_handle *) chk_malloc(sizeof *h); + obj_t *stream = cobj((void *) h, stream_t, &stdio_ops.cobj_ops); h->f = f; h->descr = descr; - return cobj((void *) h, stream_t, &stdio_ops.cobj_ops); + return stream; } obj_t *make_pipe_stream(FILE *f, obj_t *descr, obj_t *input, obj_t *output) { struct stdio_handle *h = (struct stdio_handle *) chk_malloc(sizeof *h); + obj_t *stream = cobj((void *) h, stream_t, &pipe_ops.cobj_ops); #ifdef BROKEN_POPEN_GETWC int dup_fd = dup(fileno(f)); FILE *dup_f = (dup_fd != -1) ? fdopen(dup_fd, output ? "w" : "r") : 0; @@ -600,7 +602,9 @@ obj_t *make_pipe_stream(FILE *f, obj_t *descr, obj_t *input, obj_t *output) fclose(dup_f); else if (dup_fd != -1) close(dup_fd); - free(h); + /* Don't leave h uninitialized; it is gc-reachable through stream cobj. */ + h->f = h->f_orig_pipe = 0; + h->descr = descr; uw_throwf(process_error, L"unable to create pipe ~a: ~a/~s", descr, num(error), string_utf8(strerror(error)), nao); } @@ -609,9 +613,9 @@ obj_t *make_pipe_stream(FILE *f, obj_t *descr, obj_t *input, obj_t *output) h->f = dup_f; #else h->f = f; - h->descr = descr; #endif - return cobj((void *) h, stream_t, &pipe_ops.cobj_ops); + h->descr = descr; + return stream; } obj_t *make_string_input_stream(obj_t *string) |