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 | |
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.
-rw-r--r-- | ChangeLog | 25 | ||||
-rw-r--r-- | hash.c | 11 | ||||
-rw-r--r-- | stream.c | 12 |
3 files changed, 41 insertions, 7 deletions
@@ -1,3 +1,28 @@ +2009-11-14 Kaz Kylheku <kkylheku@gmail.com> + + 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. + + * hash.c (make_hash): Fix cobj construction order. + + * stream.c (make_stdio_stream): Fix cobj construction order. + (make_pipe_stream): Fix cobj construction order. Also + noticed and fixed a bug: h->descr field not being initialized + in the currently enabled BROKEN_POPEN_GETWC variant of the code. + 2009-11-13 Kaz Kylheku <kkylheku@gmail.com> New testcase which does some UTF-8 scanning, Unicode regexes, @@ -223,11 +223,16 @@ obj_t *make_hash(obj_t *weak_keys, obj_t *weak_vals) int flags = ((weak_vals != nil) << 1) | (weak_keys != nil); struct hash *h = (struct hash *) chk_malloc(sizeof *h); obj_t *mod = num(256); + obj_t *table = vector(mod); + obj_t *hash = cobj((void *) h, hash_t, &hash_ops); + + vec_set_fill(table, mod); + h->flags = (hash_flags_t) flags; h->modulus = c_num(mod); - h->table = vector(mod); - vec_set_fill(h->table, mod); - return cobj((void *) h, hash_t, &hash_ops); + h->table = table; + + return hash; } obj_t **gethash_l(obj_t *hash, obj_t *key) @@ -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) |