Skip to content

Commit 72854dc

Browse files
authored
Fix getfield of potentially undef inline immutable field (#37511)
The undef ref error may be thrown at the wrong time or not at all and may cause crashes.
1 parent 2e07bd7 commit 72854dc

File tree

2 files changed

+74
-4
lines changed

2 files changed

+74
-4
lines changed

src/cgutils.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,16 +1687,18 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx,
16871687
else if (is_tupletype_homogeneous(stt->types)) {
16881688
assert(nfields > 0); // nf == 0 trapped by all_pointers case
16891689
jl_value_t *jft = jl_svecref(stt->types, 0);
1690+
assert(jl_is_concrete_type(jft));
16901691
idx = idx0();
16911692
Value *ptr = maybe_decay_tracked(ctx, data_pointer(ctx, strct));
1692-
if (!stt->mutabl && !(maybe_null && jft == (jl_value_t*)jl_bool_type)) {
1693+
if (!stt->mutabl && !(maybe_null && (jft == (jl_value_t*)jl_bool_type ||
1694+
((jl_datatype_t*)jft)->layout->npointers))) {
16931695
// just compute the pointer and let user load it when necessary
16941696
Type *fty = julia_type_to_llvm(ctx, jft);
16951697
Value *addr = ctx.builder.CreateInBoundsGEP(fty, emit_bitcast(ctx, ptr, PointerType::get(fty, 0)), idx);
16961698
*ret = mark_julia_slot(addr, jft, NULL, strct.tbaa);
16971699
return true;
16981700
}
1699-
*ret = typed_load(ctx, ptr, idx, jft, strct.tbaa, nullptr, false);
1701+
*ret = typed_load(ctx, ptr, idx, jft, strct.tbaa, nullptr, maybe_null);
17001702
return true;
17011703
}
17021704
else if (strct.isboxed) {
@@ -1787,12 +1789,14 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st
17871789
}
17881790
return mark_julia_slot(addr, jfty, tindex, tbaa);
17891791
}
1790-
else if (!jt->mutabl && !(maybe_null && jfty == (jl_value_t*)jl_bool_type)) {
1792+
assert(jl_is_concrete_type(jfty));
1793+
if (!jt->mutabl && !(maybe_null && (jfty == (jl_value_t*)jl_bool_type ||
1794+
((jl_datatype_t*)jfty)->layout->npointers))) {
17911795
// just compute the pointer and let user load it when necessary
17921796
return mark_julia_slot(addr, jfty, NULL, tbaa);
17931797
}
17941798
unsigned align = jl_field_align(jt, idx);
1795-
return typed_load(ctx, addr, NULL, jfty, tbaa, nullptr, true, align);
1799+
return typed_load(ctx, addr, NULL, jfty, tbaa, nullptr, maybe_null, align);
17961800
}
17971801
else if (isa<UndefValue>(strct.V)) {
17981802
return jl_cgval_t();

test/core.jl

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7330,3 +7330,69 @@ function c37265_2(d)
73307330
e
73317331
end
73327332
@test_throws TypeError c37265_2(0)
7333+
7334+
struct PointerImmutable
7335+
a::Any
7336+
b::Int
7337+
end
7338+
struct NullableHomogeneousPointerImmutable
7339+
x1::PointerImmutable
7340+
x2::PointerImmutable
7341+
x3::PointerImmutable
7342+
NullableHomogeneousPointerImmutable() = new()
7343+
NullableHomogeneousPointerImmutable(x1) = new(x1)
7344+
NullableHomogeneousPointerImmutable(x1, x2) = new(x1, x2)
7345+
NullableHomogeneousPointerImmutable(x1, x2, x3) = new(x1, x2, x3)
7346+
end
7347+
7348+
function getfield_knownindex_unused(v)
7349+
v.x1
7350+
return
7351+
end
7352+
7353+
function getfield_unknownindex_unused(v, n)
7354+
getfield(v, n)
7355+
return
7356+
end
7357+
7358+
function getfield_knownindex_used1(r, v)
7359+
fld = v.x1
7360+
r[] += 1
7361+
return fld
7362+
end
7363+
7364+
function getfield_knownindex_used2(r, v)
7365+
fld = v.x1
7366+
r[] += 1
7367+
return fld.a
7368+
end
7369+
7370+
function getfield_knownindex_used3(r, v)
7371+
fld = v.x1
7372+
r[] += 1
7373+
return fld.b
7374+
end
7375+
7376+
let v = NullableHomogeneousPointerImmutable(),
7377+
v2 = NullableHomogeneousPointerImmutable(PointerImmutable(1, 2)),
7378+
r = Ref(0)
7379+
@test_throws UndefRefError getfield_knownindex_unused(v)
7380+
@test_throws UndefRefError getfield_unknownindex_unused(v, 1)
7381+
@test_throws UndefRefError getfield_unknownindex_unused(v, :x1)
7382+
@test_throws UndefRefError getfield_knownindex_used1(r, v)
7383+
@test r[] == 0
7384+
@test_throws UndefRefError getfield_knownindex_used2(r, v)
7385+
@test r[] == 0
7386+
@test_throws UndefRefError getfield_knownindex_used3(r, v)
7387+
@test r[] == 0
7388+
7389+
@test getfield_knownindex_unused(v2) === nothing
7390+
@test getfield_unknownindex_unused(v2, 1) === nothing
7391+
@test getfield_unknownindex_unused(v2, :x1) === nothing
7392+
@test getfield_knownindex_used1(r, v2) === PointerImmutable(1, 2)
7393+
@test r[] == 1
7394+
@test getfield_knownindex_used2(r, v2) === 1
7395+
@test r[] == 2
7396+
@test getfield_knownindex_used3(r, v2) === 2
7397+
@test r[] == 3
7398+
end

0 commit comments

Comments
 (0)