Skip to content

Commit

Permalink
Fix getfield of potentially undef inline immutable field (#37511)
Browse files Browse the repository at this point in the history
The undef ref error may be thrown at the wrong time or not at all and may cause crashes.
  • Loading branch information
yuyichao authored Sep 13, 2020
1 parent 2e07bd7 commit 72854dc
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 4 deletions.
12 changes: 8 additions & 4 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1687,16 +1687,18 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx,
else if (is_tupletype_homogeneous(stt->types)) {
assert(nfields > 0); // nf == 0 trapped by all_pointers case
jl_value_t *jft = jl_svecref(stt->types, 0);
assert(jl_is_concrete_type(jft));
idx = idx0();
Value *ptr = maybe_decay_tracked(ctx, data_pointer(ctx, strct));
if (!stt->mutabl && !(maybe_null && jft == (jl_value_t*)jl_bool_type)) {
if (!stt->mutabl && !(maybe_null && (jft == (jl_value_t*)jl_bool_type ||
((jl_datatype_t*)jft)->layout->npointers))) {
// just compute the pointer and let user load it when necessary
Type *fty = julia_type_to_llvm(ctx, jft);
Value *addr = ctx.builder.CreateInBoundsGEP(fty, emit_bitcast(ctx, ptr, PointerType::get(fty, 0)), idx);
*ret = mark_julia_slot(addr, jft, NULL, strct.tbaa);
return true;
}
*ret = typed_load(ctx, ptr, idx, jft, strct.tbaa, nullptr, false);
*ret = typed_load(ctx, ptr, idx, jft, strct.tbaa, nullptr, maybe_null);
return true;
}
else if (strct.isboxed) {
Expand Down Expand Up @@ -1787,12 +1789,14 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st
}
return mark_julia_slot(addr, jfty, tindex, tbaa);
}
else if (!jt->mutabl && !(maybe_null && jfty == (jl_value_t*)jl_bool_type)) {
assert(jl_is_concrete_type(jfty));
if (!jt->mutabl && !(maybe_null && (jfty == (jl_value_t*)jl_bool_type ||
((jl_datatype_t*)jfty)->layout->npointers))) {
// just compute the pointer and let user load it when necessary
return mark_julia_slot(addr, jfty, NULL, tbaa);
}
unsigned align = jl_field_align(jt, idx);
return typed_load(ctx, addr, NULL, jfty, tbaa, nullptr, true, align);
return typed_load(ctx, addr, NULL, jfty, tbaa, nullptr, maybe_null, align);
}
else if (isa<UndefValue>(strct.V)) {
return jl_cgval_t();
Expand Down
66 changes: 66 additions & 0 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7330,3 +7330,69 @@ function c37265_2(d)
e
end
@test_throws TypeError c37265_2(0)

struct PointerImmutable
a::Any
b::Int
end
struct NullableHomogeneousPointerImmutable
x1::PointerImmutable
x2::PointerImmutable
x3::PointerImmutable
NullableHomogeneousPointerImmutable() = new()
NullableHomogeneousPointerImmutable(x1) = new(x1)
NullableHomogeneousPointerImmutable(x1, x2) = new(x1, x2)
NullableHomogeneousPointerImmutable(x1, x2, x3) = new(x1, x2, x3)
end

function getfield_knownindex_unused(v)
v.x1
return
end

function getfield_unknownindex_unused(v, n)
getfield(v, n)
return
end

function getfield_knownindex_used1(r, v)
fld = v.x1
r[] += 1
return fld
end

function getfield_knownindex_used2(r, v)
fld = v.x1
r[] += 1
return fld.a
end

function getfield_knownindex_used3(r, v)
fld = v.x1
r[] += 1
return fld.b
end

let v = NullableHomogeneousPointerImmutable(),
v2 = NullableHomogeneousPointerImmutable(PointerImmutable(1, 2)),
r = Ref(0)
@test_throws UndefRefError getfield_knownindex_unused(v)
@test_throws UndefRefError getfield_unknownindex_unused(v, 1)
@test_throws UndefRefError getfield_unknownindex_unused(v, :x1)
@test_throws UndefRefError getfield_knownindex_used1(r, v)
@test r[] == 0
@test_throws UndefRefError getfield_knownindex_used2(r, v)
@test r[] == 0
@test_throws UndefRefError getfield_knownindex_used3(r, v)
@test r[] == 0

@test getfield_knownindex_unused(v2) === nothing
@test getfield_unknownindex_unused(v2, 1) === nothing
@test getfield_unknownindex_unused(v2, :x1) === nothing
@test getfield_knownindex_used1(r, v2) === PointerImmutable(1, 2)
@test r[] == 1
@test getfield_knownindex_used2(r, v2) === 1
@test r[] == 2
@test getfield_knownindex_used3(r, v2) === 2
@test r[] == 3
end

0 comments on commit 72854dc

Please sign in to comment.