Skip to content

Commit fbd7c96

Browse files
committed
codegen: on alignment incongruence, replace assert by jl_error
It is possible that LLVM and Julia disagree on the offsets of struct fields. This has been observed in JuliaLang#32414 in cases like Tuple{Float64, NTuple{8, VecElement{Float64}}} where LLVM wants to align the `vec` on 64 bytes (adding 56 bytes of padding after the first `Float64`) but Julia refusing to align like that because it can't guarantee that on the heap: https://github.com/JuliaLang/julia/blob/c7e9d9f8ade647582c6635c8c9a587f2360af404/src/datatype.c#L453 There is no easy solution this I can see, but since this can be triggered from pure Julia, the least we can do is not abort the program. For this reason, this commit replaces the assert by jl_error. To be able to give a sort-of meaningful error message, we return a sentinel value from `convert_struct_offset` and generate an error message in the caller.
1 parent c7e9d9f commit fbd7c96

File tree

1 file changed

+32
-5
lines changed

1 file changed

+32
-5
lines changed

src/cgutils.cpp

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,10 @@ static unsigned convert_struct_offset(Type *lty, unsigned byte_offset)
511511
const DataLayout &DL = jl_data_layout;
512512
const StructLayout *SL = DL.getStructLayout(cast<StructType>(lty));
513513
unsigned idx = SL->getElementContainingOffset(byte_offset);
514-
assert(SL->getElementOffset(idx) == byte_offset);
514+
if(SL->getElementOffset(idx) != byte_offset) {
515+
// sentinel error value
516+
return (unsigned)(-1);
517+
}
515518
return idx;
516519
}
517520

@@ -1692,9 +1695,15 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st
16921695
else if (!jl_field_isptr(jt, idx) && jl_is_uniontype(jfty)) {
16931696
int fsz = jl_field_size(jt, idx) - 1;
16941697
unsigned ptindex = convert_struct_offset(ctx, T, byte_offset + fsz);
1698+
if(ptindex == (unsigned)(-1)) {
1699+
jl_errorf("Cannot generate accessor code because of incompatible alignment requirements");
1700+
}
16951701
AllocaInst *lv = NULL;
16961702
if (fsz > 0) {
16971703
unsigned st_idx = convert_struct_offset(ctx, T, byte_offset);
1704+
if(ptindex == (unsigned)(-1)) {
1705+
jl_errorf("Cannot generate accessor code because of incompatible alignment requirements");
1706+
}
16981707
IntegerType *ET = cast<IntegerType>(T->getStructElementType(st_idx));
16991708
unsigned align = (ET->getBitWidth() + 7) / 8;
17001709
lv = emit_static_alloca(ctx, ET);
@@ -1724,12 +1733,16 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st
17241733
}
17251734
else {
17261735
unsigned st_idx;
1727-
if (isa<ArrayType>(T))
1736+
if (isa<ArrayType>(T)) {
17281737
st_idx = idx;
1729-
else if (isa<StructType>(T))
1738+
} else if (isa<StructType>(T)) {
17301739
st_idx = convert_struct_offset(ctx, T, byte_offset);
1731-
else
1740+
if(st_idx == (unsigned)(-1)) {
1741+
jl_errorf("Cannot generate accessor code because of incompatible alignment requirements");
1742+
}
1743+
} else {
17321744
llvm_unreachable("encountered incompatible type for a struct");
1745+
}
17331746
fldv = ctx.builder.CreateExtractValue(obj, makeArrayRef(st_idx));
17341747
}
17351748
if (maybe_null && jl_field_isptr(jt, idx))
@@ -2107,8 +2120,12 @@ static jl_value_t *static_constant_instance(Constant *constant, jl_value_t *jt)
21072120
return NULL; // TODO: handle this?
21082121
}
21092122
unsigned llvm_idx = i;
2110-
if (i > 0 && isa<StructType>(constant->getType()))
2123+
if (i > 0 && isa<StructType>(constant->getType())) {
21112124
llvm_idx = convert_struct_offset(constant->getType(), jl_field_offset(jst, i));
2125+
if(llvm_idx == (unsigned)(-1)) {
2126+
jl_errorf("Cannot create an static instance of %s because of incompatible alignment requirements", jl_symbol_name(jst->name->name));
2127+
}
2128+
}
21122129
Constant *fld = constant->getAggregateElement(llvm_idx);
21132130
flds[i] = static_constant_instance(fld, ft);
21142131
if (flds[i] == NULL) {
@@ -2617,6 +2634,10 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg
26172634
Value *dest = NULL;
26182635
unsigned offs = jl_field_offset(sty, i);
26192636
unsigned llvm_idx = (i > 0 && isa<StructType>(lt)) ? convert_struct_offset(ctx, lt, offs) : i;
2637+
if(llvm_idx == (unsigned)(-1)) {
2638+
jl_errorf("Cannot create an instance of %s because of incompatible alignment requirements", jl_symbol_name(sty->name->name));
2639+
}
2640+
26202641
if (!init_as_value) {
26212642
// avoid unboxing the argument explicitly
26222643
// and use memcpy instead
@@ -2640,6 +2661,9 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg
26402661
// then load it and combine with the tindex.
26412662
// But more efficient to just store it directly.
26422663
unsigned ptindex = convert_struct_offset(ctx, lt, offs + fsz);
2664+
if(ptindex == (unsigned)(-1)) {
2665+
jl_errorf("Cannot create an instance of %s because of incompatible alignment requirements", jl_symbol_name(sty->name->name));
2666+
}
26432667
if (fsz > 0 && !fval_info.isghost) {
26442668
Type *ET = IntegerType::get(jl_LLVMContext, 8 * al);
26452669
assert(lt->getStructElementType(llvm_idx) == ET);
@@ -2694,6 +2718,9 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg
26942718
unsigned offs = jl_field_offset(sty, i);
26952719
int fsz = jl_field_size(sty, i) - 1;
26962720
unsigned llvm_idx = convert_struct_offset(ctx, cast<StructType>(lt), offs + fsz);
2721+
if(llvm_idx == (unsigned)(-1)) {
2722+
jl_errorf("Cannot create an instance of %s because of incompatible alignment requirements", jl_symbol_name(sty->name->name));
2723+
}
26972724
if (init_as_value)
26982725
strct = ctx.builder.CreateInsertValue(strct, ConstantInt::get(T_int8, 0), makeArrayRef(llvm_idx));
26992726
else

0 commit comments

Comments
 (0)