summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog25
-rw-r--r--hash.c11
-rw-r--r--stream.c12
3 files changed, 41 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index c3b8dc4d..32a9adca 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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,
diff --git a/hash.c b/hash.c
index 86ceb340..0b7c099d 100644
--- a/hash.c
+++ b/hash.c
@@ -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)
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)