summaryrefslogtreecommitdiffstats
path: root/stream.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2009-11-14 10:00:37 -0800
committerKaz Kylheku <kaz@kylheku.com>2009-11-14 10:00:37 -0800
commit9a5d3288441c27c9adef949bdf09161446915dec (patch)
tree1a3049fdbeb713d6e75688961004bf74647c7d71 /stream.c
parentfe2f8d7123f22cf7755330ac8b289bc3cd838af3 (diff)
downloadtxr-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.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/stream.c b/stream.c
index e2618a03..282a5b94 100644
--- a/stream.c
+++ b/stream.c
@@ -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)