avoid crash when interrupting bytecode unmarshal
Interrupting bytecode unmarshal for syntax objects could leave half-constructed values in a table that is intended to resolve graph structure. Clear out work towards a graph construction when interrupted. The most common symptom of half-constructed syntax objects was a crash after a Ctl-C during startup.
This commit is contained in:
parent
dfef5b43fc
commit
31549082e6
|
@ -246,7 +246,9 @@ static int mark_unmarshal_tables_MARK(void *p, struct NewGC *gc) {
|
|||
#ifndef GC_NO_MARK_PROCEDURE_NEEDED
|
||||
Scheme_Unmarshal_Tables *ut = (Scheme_Unmarshal_Tables *)p;
|
||||
gcMARK2(ut->rns, gc);
|
||||
gcMARK2(ut->current_rns, gc);
|
||||
gcMARK2(ut->multi_scope_pairs, gc);
|
||||
gcMARK2(ut->current_multi_scope_pairs, gc);
|
||||
gcMARK2(ut->rp, gc);
|
||||
gcMARK2(ut->decoded, gc);
|
||||
# ifdef GC_NO_SIZE_NEEDED_FROM_PROCS
|
||||
|
@ -262,7 +264,9 @@ static int mark_unmarshal_tables_FIXUP(void *p, struct NewGC *gc) {
|
|||
#ifndef GC_NO_FIXUP_PROCEDURE_NEEDED
|
||||
Scheme_Unmarshal_Tables *ut = (Scheme_Unmarshal_Tables *)p;
|
||||
gcFIXUP2(ut->rns, gc);
|
||||
gcFIXUP2(ut->current_rns, gc);
|
||||
gcFIXUP2(ut->multi_scope_pairs, gc);
|
||||
gcFIXUP2(ut->current_multi_scope_pairs, gc);
|
||||
gcFIXUP2(ut->rp, gc);
|
||||
gcFIXUP2(ut->decoded, gc);
|
||||
# ifdef GC_NO_SIZE_NEEDED_FROM_PROCS
|
||||
|
|
|
@ -2326,7 +2326,9 @@ mark_unmarshal_tables {
|
|||
mark:
|
||||
Scheme_Unmarshal_Tables *ut = (Scheme_Unmarshal_Tables *)p;
|
||||
gcMARK2(ut->rns, gc);
|
||||
gcMARK2(ut->current_rns, gc);
|
||||
gcMARK2(ut->multi_scope_pairs, gc);
|
||||
gcMARK2(ut->current_multi_scope_pairs, gc);
|
||||
gcMARK2(ut->rp, gc);
|
||||
gcMARK2(ut->decoded, gc);
|
||||
size:
|
||||
|
|
|
@ -4397,6 +4397,34 @@ static void make_ut(CPort *port)
|
|||
port->ut->multi_scope_pairs = rht;
|
||||
}
|
||||
|
||||
static void prepare_current_unmarshal(Scheme_Unmarshal_Tables *ut)
|
||||
{
|
||||
/* in case a previous unmarshal was interrupted: */
|
||||
ut->current_rns = NULL;
|
||||
ut->current_multi_scope_pairs = NULL;
|
||||
}
|
||||
|
||||
static void merge_ht(Scheme_Hash_Table *f, Scheme_Hash_Table *t)
|
||||
{
|
||||
int i;
|
||||
for (i = f->size; i--; ) {
|
||||
if (f->vals[i])
|
||||
scheme_hash_set(t, f->keys[i], f->vals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void complete_current_unmarshal(Scheme_Unmarshal_Tables *ut)
|
||||
{
|
||||
if (ut->current_rns) {
|
||||
merge_ht(ut->current_rns, ut->rns);
|
||||
ut->current_rns = NULL;
|
||||
}
|
||||
if (ut->current_multi_scope_pairs) {
|
||||
merge_ht(ut->current_multi_scope_pairs, ut->multi_scope_pairs);
|
||||
ut->current_multi_scope_pairs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Since read_compact_number is called often, we want it to be
|
||||
a cheap call in 3m, so avoid anything that allocated --- even
|
||||
error reporting, since we can make up a valid number. */
|
||||
|
@ -4563,20 +4591,33 @@ static Scheme_Object *resolve_symtab_refs(Scheme_Object *v, CPort *port)
|
|||
if (SCHEME_NULLP(port->symtab_refs))
|
||||
return v;
|
||||
|
||||
v = scheme_make_pair(v, port->symtab_refs);
|
||||
if (v) {
|
||||
v = scheme_make_pair(v, port->symtab_refs);
|
||||
|
||||
v = resolve_references(v, port->orig_port, NULL,
|
||||
scheme_make_hash_table(SCHEME_hash_ptr),
|
||||
scheme_make_hash_table(SCHEME_hash_ptr),
|
||||
0, 0);
|
||||
|
||||
l = SCHEME_CDR(v);
|
||||
} else
|
||||
l = port->symtab_refs;
|
||||
|
||||
v = resolve_references(v, port->orig_port, NULL,
|
||||
scheme_make_hash_table(SCHEME_hash_ptr),
|
||||
scheme_make_hash_table(SCHEME_hash_ptr),
|
||||
0, 0);
|
||||
|
||||
for (l = SCHEME_CDR(v); !SCHEME_NULLP(l); l = SCHEME_CDR(l)) {
|
||||
port->symtab[SCHEME_INT_VAL(SCHEME_CAR(SCHEME_CAR(l)))] = SCHEME_CDR(SCHEME_CAR(l));
|
||||
for (; !SCHEME_NULLP(l); l = SCHEME_CDR(l)) {
|
||||
if (v)
|
||||
port->symtab[SCHEME_INT_VAL(SCHEME_CAR(SCHEME_CAR(l)))] = SCHEME_CDR(SCHEME_CAR(l));
|
||||
else {
|
||||
/* interrupted; discard partial constructions */
|
||||
port->symtab[SCHEME_INT_VAL(SCHEME_CAR(SCHEME_CAR(l)))] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
port->symtab_refs = scheme_null;
|
||||
|
||||
return SCHEME_CAR(v);
|
||||
|
||||
if (v)
|
||||
return SCHEME_CAR(v);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Scheme_Object *read_compact(CPort *port, int use_stack);
|
||||
|
@ -4804,6 +4845,7 @@ static Scheme_Object *read_compact(CPort *port, int use_stack)
|
|||
save_ht = *port->ht;
|
||||
*port->ht = NULL;
|
||||
|
||||
prepare_current_unmarshal(port->ut);
|
||||
v = read_compact(port, 1);
|
||||
|
||||
if (!SCHEME_NULLP(port->symtab_refs))
|
||||
|
@ -4822,6 +4864,7 @@ static Scheme_Object *read_compact(CPort *port, int use_stack)
|
|||
scheme_num_read_syntax_objects++;
|
||||
if (!v)
|
||||
scheme_ill_formed_code(port);
|
||||
complete_current_unmarshal(port->ut);
|
||||
}
|
||||
break;
|
||||
case CPT_MARSHALLED:
|
||||
|
@ -5936,6 +5979,9 @@ Scheme_Object *scheme_load_delayed_code(int _which, Scheme_Load_Delay *_delay_in
|
|||
|
||||
rp->pos = delay_info->shared_offsets[which - 1];
|
||||
|
||||
if (delay_info->ut)
|
||||
prepare_current_unmarshal(delay_info->ut);
|
||||
|
||||
/* Perform the read, catching escapes so we can clean up: */
|
||||
savebuf = scheme_current_thread->error_buf;
|
||||
scheme_current_thread->error_buf = &newbuf;
|
||||
|
@ -5954,8 +6000,10 @@ Scheme_Object *scheme_load_delayed_code(int _which, Scheme_Load_Delay *_delay_in
|
|||
v = resolve_symtab_refs(v, rp);
|
||||
|
||||
delay_info->current_rp = old_rp;
|
||||
if (delay_info->ut)
|
||||
if (delay_info->ut) {
|
||||
delay_info->ut->rp = old_rp;
|
||||
complete_current_unmarshal(delay_info->ut);
|
||||
}
|
||||
|
||||
if (!old_rp && !delay_info->perma_cache) {
|
||||
/* No one using the cache, to register it to be cleaned up */
|
||||
|
|
|
@ -35,6 +35,17 @@
|
|||
#define HOOK_SHARED_OK /* EMPTY */
|
||||
#endif
|
||||
|
||||
#ifdef OS_X
|
||||
# define MZ_CHECK_ASSERTS
|
||||
#endif
|
||||
|
||||
#ifdef MZ_CHECK_ASSERTS
|
||||
# include <assert.h>
|
||||
# define MZ_ASSERT(x) assert(x)
|
||||
#else
|
||||
# define MZ_ASSERT(x) /* empty */
|
||||
#endif
|
||||
|
||||
/*========================================================================*/
|
||||
/* optimization flags */
|
||||
/*========================================================================*/
|
||||
|
@ -3377,7 +3388,9 @@ void scheme_marshal_pop_refs(Scheme_Marshal_Tables *mt, int keep);
|
|||
typedef struct Scheme_Unmarshal_Tables {
|
||||
MZTAG_IF_REQUIRED
|
||||
Scheme_Hash_Table *rns;
|
||||
Scheme_Hash_Table *current_rns; /* in-progress unmarshal, commit to `rns` at end */
|
||||
Scheme_Hash_Table *multi_scope_pairs; /* records conversions */
|
||||
Scheme_Hash_Table *current_multi_scope_pairs; /* commit to `multi_scope_pairs` at end */
|
||||
struct CPort *rp;
|
||||
char *decoded;
|
||||
mzlonglong bytecode_hash;
|
||||
|
|
|
@ -263,16 +263,7 @@ int stx_alloc_prop_table, stx_skip_alloc_prop_table;
|
|||
- <insp> => clean, but inspector needs to be proagated to children
|
||||
- (list <insp/#f> <insp> ...+) [interned] => armed; first inspector is to propagate */
|
||||
|
||||
#ifdef OS_X
|
||||
# define CHECK_STX_ASSERTS
|
||||
#endif
|
||||
|
||||
#ifdef CHECK_STX_ASSERTS
|
||||
# include <assert.h>
|
||||
# define STX_ASSERT(x) assert(x)
|
||||
#else
|
||||
# define STX_ASSERT(x) /* empty */
|
||||
#endif
|
||||
#define STX_ASSERT(x) MZ_ASSERT(x)
|
||||
|
||||
static Scheme_Object *make_vector3(Scheme_Object *a, Scheme_Object *b, Scheme_Object *c)
|
||||
{
|
||||
|
@ -6531,6 +6522,37 @@ Scheme_Object *scheme_syntax_to_datum(Scheme_Object *stx, int with_scopes,
|
|||
|
||||
#define return_NULL return NULL
|
||||
|
||||
Scheme_Object *scheme_hash_get_either(Scheme_Hash_Table *ht, Scheme_Hash_Table *ht2,
|
||||
Scheme_Object *key)
|
||||
{
|
||||
Scheme_Object *val;
|
||||
val = scheme_hash_get(ht, key);
|
||||
if (val)
|
||||
return val;
|
||||
else if (ht2)
|
||||
return scheme_hash_get(ht2, key);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ensure_current_rns(Scheme_Unmarshal_Tables *ut)
|
||||
{
|
||||
Scheme_Hash_Table *rht;
|
||||
if (!ut->current_rns) {
|
||||
rht = scheme_make_hash_table(SCHEME_hash_ptr);
|
||||
ut->current_rns = rht;
|
||||
}
|
||||
}
|
||||
|
||||
static void ensure_current_multi_scope_pairs(Scheme_Unmarshal_Tables *ut)
|
||||
{
|
||||
Scheme_Hash_Table *rht;
|
||||
if (!ut->current_multi_scope_pairs) {
|
||||
rht = scheme_make_hash_table(SCHEME_hash_ptr);
|
||||
ut->current_multi_scope_pairs = rht;
|
||||
}
|
||||
}
|
||||
|
||||
Scheme_Scope_Set *list_to_scope_set(Scheme_Object *l, Scheme_Unmarshal_Tables *ut)
|
||||
{
|
||||
Scheme_Scope_Set *scopes = NULL;
|
||||
|
@ -6538,7 +6560,7 @@ Scheme_Scope_Set *list_to_scope_set(Scheme_Object *l, Scheme_Unmarshal_Tables *u
|
|||
|
||||
while (!SCHEME_NULLP(l)) {
|
||||
if (!SCHEME_PAIRP(l)) return_NULL;
|
||||
scopes = (Scheme_Scope_Set *)scheme_hash_get(ut->rns, l);
|
||||
scopes = (Scheme_Scope_Set *)scheme_hash_get_either(ut->rns, ut->current_rns, l);
|
||||
if (scopes)
|
||||
break;
|
||||
r = scheme_make_pair(l, r);
|
||||
|
@ -6554,7 +6576,8 @@ Scheme_Scope_Set *list_to_scope_set(Scheme_Object *l, Scheme_Unmarshal_Tables *u
|
|||
if (!scope) return_NULL;
|
||||
|
||||
scopes = scope_set_set(scopes, scope, scheme_true);
|
||||
scheme_hash_set(ut->rns, l, (Scheme_Object *)scopes);
|
||||
ensure_current_rns(ut);
|
||||
scheme_hash_set(ut->current_rns, l, (Scheme_Object *)scopes);
|
||||
|
||||
r = SCHEME_CDR(r);
|
||||
}
|
||||
|
@ -6571,7 +6594,7 @@ static Scheme_Hash_Table *vector_to_multi_scope(Scheme_Object *mht, Scheme_Unmar
|
|||
|
||||
if (!SCHEME_VECTORP(mht)) return_NULL;
|
||||
|
||||
multi_scope = (Scheme_Hash_Table *)scheme_hash_get(ut->rns, mht);
|
||||
multi_scope = (Scheme_Hash_Table *)scheme_hash_get_either(ut->rns, ut->current_rns, mht);
|
||||
if (multi_scope) return multi_scope;
|
||||
|
||||
multi_scope = scheme_make_hash_table(SCHEME_hash_ptr);
|
||||
|
@ -6591,7 +6614,8 @@ static Scheme_Hash_Table *vector_to_multi_scope(Scheme_Object *mht, Scheme_Unmar
|
|||
len -= 1;
|
||||
|
||||
/* A multi-scope can refer back to itself via free-id=? info: */
|
||||
scheme_hash_set(ut->rns, mht, (Scheme_Object *)multi_scope);
|
||||
ensure_current_rns(ut);
|
||||
scheme_hash_set(ut->current_rns, mht, (Scheme_Object *)multi_scope);
|
||||
|
||||
for (i = 0; i < len; i += 2) {
|
||||
if (!SCHEME_PHASEP(SCHEME_VEC_ELS(mht)[i]))
|
||||
|
@ -6633,9 +6657,9 @@ Scheme_Object *unmarshal_multi_scopes(Scheme_Object *multi_scopes,
|
|||
if (!SCHEME_PAIRP(l)) return_NULL;
|
||||
if (!SCHEME_PAIRP(SCHEME_CAR(l))) return_NULL;
|
||||
|
||||
p = scheme_hash_get(ut->multi_scope_pairs, l);
|
||||
p = scheme_hash_get_either(ut->multi_scope_pairs, ut->current_multi_scope_pairs, l);
|
||||
if (!p) {
|
||||
p = scheme_hash_get(ut->multi_scope_pairs, SCHEME_CAR(l));
|
||||
p = scheme_hash_get_either(ut->multi_scope_pairs, ut->current_multi_scope_pairs, SCHEME_CAR(l));
|
||||
if (p) {
|
||||
p = scheme_make_pair(p, scheme_null);
|
||||
} else {
|
||||
|
@ -6645,11 +6669,13 @@ Scheme_Object *unmarshal_multi_scopes(Scheme_Object *multi_scopes,
|
|||
if (!SCHEME_PHASE_SHIFTP(SCHEME_CDR(SCHEME_CAR(l)))) return_NULL;
|
||||
p = scheme_make_pair((Scheme_Object *)multi_scope,
|
||||
SCHEME_CDR(SCHEME_CAR(l)));
|
||||
scheme_hash_set(ut->multi_scope_pairs, SCHEME_CAR(l), p);
|
||||
ensure_current_multi_scope_pairs(ut);
|
||||
scheme_hash_set(ut->current_multi_scope_pairs, SCHEME_CAR(l), p);
|
||||
} else
|
||||
return_NULL;
|
||||
}
|
||||
scheme_hash_set(ut->multi_scope_pairs, SCHEME_CAR(l), p);
|
||||
ensure_current_multi_scope_pairs(ut);
|
||||
scheme_hash_set(ut->current_multi_scope_pairs, SCHEME_CAR(l), p);
|
||||
p = scheme_make_pair(p, scheme_null);
|
||||
stop = 0;
|
||||
} else
|
||||
|
@ -6663,8 +6689,10 @@ Scheme_Object *unmarshal_multi_scopes(Scheme_Object *multi_scopes,
|
|||
|
||||
if (stop)
|
||||
break;
|
||||
else
|
||||
scheme_hash_set(ut->multi_scope_pairs, l, p);
|
||||
else {
|
||||
ensure_current_multi_scope_pairs(ut);
|
||||
scheme_hash_set(ut->current_multi_scope_pairs, l, p);
|
||||
}
|
||||
}
|
||||
|
||||
if (SCHEME_FALLBACKP(mm_l)) {
|
||||
|
@ -6694,7 +6722,7 @@ static Scheme_Object *datum_to_wraps(Scheme_Object *w,
|
|||
Scheme_Scope_Set *scopes;
|
||||
Scheme_Object *l;
|
||||
|
||||
l = scheme_hash_get(ut->rns, w);
|
||||
l = scheme_hash_get_either(ut->rns, ut->current_rns, w);
|
||||
if (l) {
|
||||
if (!SCHEME_PAIRP(l)
|
||||
|| !SAME_TYPE(SCHEME_TYPE(SCHEME_CAR(l)), scheme_scope_table_type))
|
||||
|
@ -6719,7 +6747,8 @@ static Scheme_Object *datum_to_wraps(Scheme_Object *w,
|
|||
st->multi_scopes = l;
|
||||
|
||||
l = scheme_make_pair((Scheme_Object *)st, SCHEME_VEC_ELS(w)[0]);
|
||||
scheme_hash_set(ut->rns, w, l);
|
||||
ensure_current_rns(ut);
|
||||
scheme_hash_set(ut->current_rns, w, l);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
@ -6828,7 +6857,7 @@ Scheme_Object *scope_unmarshal_content(Scheme_Object *box, Scheme_Unmarshal_Tabl
|
|||
if (SAME_OBJ(box, root_scope))
|
||||
return root_scope;
|
||||
|
||||
r = scheme_hash_get(ut->rns, box);
|
||||
r = scheme_hash_get_either(ut->rns, ut->current_rns, box);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
|
@ -6848,7 +6877,9 @@ Scheme_Object *scope_unmarshal_content(Scheme_Object *box, Scheme_Unmarshal_Tabl
|
|||
c = SCHEME_CDR(c);
|
||||
} else
|
||||
m = scheme_new_scope(SCHEME_STX_MACRO_SCOPE);
|
||||
scheme_hash_set(ut->rns, box, m);
|
||||
|
||||
ensure_current_rns(ut);
|
||||
scheme_hash_set(ut->current_rns, box, m);
|
||||
/* Since we've created the scope before unmarshaling its content,
|
||||
cycles among scopes are ok. */
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user