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:
parent
4b02c169d7
commit
ba1f5be532
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in New Issue
Block a user