fix potential crash when printing a changing hash table

If a mutable hash table changes while it's being printed,
various parts of the printing function could see a mismatch
between the current size and an old array size. To avoid this
problem, extract the size whenever extracting the array.
This commit is contained in:
Matthew Flatt 2016-11-28 18:17:36 -07:00
parent 4b02c169d7
commit ba1f5be532
2 changed files with 30 additions and 6 deletions

View File

@ -268,6 +268,26 @@
(loop (sub1 i))))))
;; ----------------------------------------
;; Check that printing a hash table doesn't crash
;; if the table changes while it's being printed
;; (or checked for cycles):
(let ()
(define ht (make-hash))
(struct trouble (t)
#:property prop:custom-write
(lambda (s p mode)
(hash-set! ht (random) 'ok)
(fprintf p "trouble")))
(for ([i (in-range 100)])
(hash-set! ht (trouble i) i))
(for ([i 20])
(define o (open-output-bytes))
(print ht o)))
;; ----------------------------------------
(report-errs)

View File

@ -651,7 +651,7 @@ static int check_cycles(Scheme_Object *obj, int for_write, Scheme_Hash_Table *ht
/* got here => printable */
Scheme_Hash_Table *t;
Scheme_Object **keys, **vals, *val, *key;
int i;
int i, size;
if (SCHEME_NP_CHAPERONEP(obj))
t = (Scheme_Hash_Table *)SCHEME_CHAPERONE_VAL(obj);
@ -660,8 +660,9 @@ static int check_cycles(Scheme_Object *obj, int for_write, Scheme_Hash_Table *ht
keys = t->keys;
vals = t->vals;
size = t->size;
res = 0;
for (i = 0; i < t->size; i++) {
for (i = 0; i < size; i++) {
if (vals[i]) {
key = keys[i];
if (!SAME_OBJ((Scheme_Object *)t, obj))
@ -928,7 +929,7 @@ static void setup_graph_table(Scheme_Object *obj, int for_write, Scheme_Hash_Tab
} else if (pp && SCHEME_CHAPERONE_HASHTPx(obj)) { /* got here => printable */
Scheme_Hash_Table *t;
Scheme_Object **keys, **vals, *val, *key;
int i;
int i, size;
if (SCHEME_NP_CHAPERONEP(obj))
t = (Scheme_Hash_Table *)SCHEME_CHAPERONE_VAL(obj);
@ -937,7 +938,8 @@ static void setup_graph_table(Scheme_Object *obj, int for_write, Scheme_Hash_Tab
keys = t->keys;
vals = t->vals;
for (i = 0; i < t->size; i++) {
size = t->size;
for (i = 0; i < size; i++) {
if (vals[i]) {
key = keys[i];
if (!SAME_OBJ((Scheme_Object *)t, obj))
@ -2360,7 +2362,7 @@ print(Scheme_Object *obj, int notdisplay, int compact, Scheme_Hash_Table *ht,
Scheme_Hash_Table *t;
Scheme_Hash_Tree *tr;
Scheme_Object **keys, **vals, *val, *key, *orig, **sorted_keys;
intptr_t i, size, count;
intptr_t i, size, count, vals_size;
int did_one = 0;
mzlonglong pos;
@ -2417,10 +2419,12 @@ print(Scheme_Object *obj, int notdisplay, int compact, Scheme_Hash_Table *ht,
keys = t->keys;
vals = t->vals;
size = t->size;
vals_size = size;
count = t->count;
} else {
keys = NULL;
vals = NULL;
vals_size = 0;
size = tr->count;
count = size;
}
@ -2451,7 +2455,7 @@ print(Scheme_Object *obj, int notdisplay, int compact, Scheme_Hash_Table *ht,
if (!SAME_OBJ(obj, orig))
val = scheme_chaperone_hash_traversal_get(orig, key, &key);
} else {
if (i < t->size) {
if (i < vals_size) {
val = vals[i];
key = keys[i];
if (!SAME_OBJ(obj, orig))