diff options
-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) |