Skip to content

Commit

Permalink
Fix getfield of potentially undef inline immutable field (JuliaLang#3…
Browse files Browse the repository at this point in the history
…7511)

The undef ref error may be thrown at the wrong time or not at all and may cause crashes.
  • Loading branch information
yuyichao committed 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.