Skip to content

Commit

Permalink
Properly mark a deleted typemap entry
Browse files Browse the repository at this point in the history
This issue possibly fixes #24951 (or at least the test case by iamed2).
We believe the original code here meant to say either:

    ((jl_typemap_entry_t*)v)->min_world = ((jl_typemap_entry_t*)v)->max_world + 1;

or

    ((jl_typemap_entry_t*)v)->max_world = ((jl_typemap_entry_t*)v)->min_world - 1;

i.e. set the range of applicable worlds to be empty. What happened instead
was that the given typemap entry that was supposed to be deleted became valid
for one particular world and that world only. Thus any code running in that
particular world may try to access the deleted typemap entry (or add a backedge
to it), causing either incorrect behavior or the assertion failure noted
in the issue. One additional complication is that these world ages are being
deserialized, i.e. they may be larger than the currently possible max world age.
This makes this slightly more likely to happen, since the current process
may work its way up to that world age and exectue some code.

In any case, there's not much value to keeping around the deserialized max or min
world, so just mark them as [1:0], as we do for other deleted entries.

Co-authored-by: Jameson Nash <jameson@juliacomputing.com>
  • Loading branch information
2 people authored and vtjnash committed Jun 14, 2018
1 parent 5ba7f20 commit b6a44fd
Showing 1 changed file with 32 additions and 21 deletions.
53 changes: 32 additions & 21 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -740,12 +740,12 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li
assert(*bp != (uintptr_t)HT_NOTFOUND);
*bp |= 1;
}
write_uint8(s->s, internal);
jl_serialize_value(s, (jl_value_t*)li->specTypes);
if (!internal)
jl_serialize_value(s, (jl_value_t*)li->def.method->sig);
else
jl_serialize_value(s, li->def.value);
write_uint8(s->s, internal);
if (!internal)
return;
jl_serialize_value(s, li->inferred);
Expand Down Expand Up @@ -1605,6 +1605,23 @@ static jl_value_t *jl_deserialize_value_method_instance(jl_serializer_state *s,
uintptr_t pos = backref_list.len;
if (usetable)
arraylist_push(&backref_list, li);
int internal = read_uint8(s->s);
if (internal == 1) {
li->min_world = 0;
li->max_world = 0;
}
else if (internal == 2) {
li->min_world = jl_world_counter;
li->max_world = ~(size_t)0;
}
else if (internal == 3) {
li->min_world = 1;
li->max_world = 0;
}
else if (internal) {
assert(0 && "corrupt deserialization state");
abort();
}

li->specTypes = (jl_value_t*)jl_deserialize_value(s, (jl_value_t**)&li->specTypes);
if (li->specTypes)
Expand All @@ -1613,7 +1630,6 @@ static jl_value_t *jl_deserialize_value_method_instance(jl_serializer_state *s,
if (li->def.value)
jl_gc_wb(li, li->def.value);

int internal = read_uint8(s->s);
if (!internal) {
assert(loc != NULL && loc != HT_NOTFOUND);
arraylist_push(&flagref_list, loc);
Expand All @@ -1633,22 +1649,6 @@ static jl_value_t *jl_deserialize_value_method_instance(jl_serializer_state *s,
li->backedges = (jl_array_t*)jl_deserialize_value(s, (jl_value_t**)&li->backedges);
if (li->backedges)
jl_gc_wb(li, li->backedges);
if (internal == 1) {
li->min_world = 0;
li->max_world = 0;
}
else if (internal == 2) {
li->min_world = jl_world_counter;
li->max_world = ~(size_t)0;
}
else if (internal == 3) {
li->min_world = 1;
li->max_world = 0;
}
else {
assert(0 && "corrupt deserialization state");
abort();
}
li->functionObjectsDecls.functionObject = NULL;
li->functionObjectsDecls.specFunctionObject = NULL;
li->inInference = 0;
Expand Down Expand Up @@ -1795,7 +1795,8 @@ static void jl_deserialize_struct(jl_serializer_state *s, jl_value_t *v, size_t
}
else {
// garbage entry - delete it :(
((jl_typemap_entry_t*)v)->min_world = ((jl_typemap_entry_t*)v)->max_world - 1;
((jl_typemap_entry_t*)v)->min_world = 1;
((jl_typemap_entry_t*)v)->max_world = 0;
}
}
}
Expand All @@ -1809,10 +1810,20 @@ static jl_value_t *jl_deserialize_typemap_entry(jl_serializer_state *s)
jl_value_t *v = jl_gc_alloc(s->ptls, jl_datatype_size(jl_typemap_entry_type), jl_typemap_entry_type);
if (n == N && s->mode != MODE_AST)
arraylist_push(&backref_list, v);
jl_typemap_entry_t* te = (jl_typemap_entry_t*)v;
te->next = (jl_typemap_entry_t*)jl_nothing; // `next` is the first field
jl_deserialize_struct(s, v, 1);
((jl_typemap_entry_t*)v)->next = (jl_typemap_entry_t*)jl_nothing;
#ifndef NDEBUG
if (te->func.value && jl_typeis(te->func.value, jl_method_instance_type)) {
assert((te->func.linfo->max_world == 0 &&
te->func.linfo->min_world == 1) ||
(te->func.linfo->max_world >= te->max_world &&
te->func.linfo->min_world <= te->min_world) &&
"corrupt typemap entry structure");
}
#endif
*pn = v;
pn = (jl_value_t**)&((jl_typemap_entry_t*)v)->next;
pn = (jl_value_t**)&te->next;
n--;
}
return te;
Expand Down

0 comments on commit b6a44fd

Please sign in to comment.