Skip to content

Commit

Permalink
more robust validation of allocation type (#49269)
Browse files Browse the repository at this point in the history
We generally hit the runtime in pretty specific places when allocations
look funky (because they are missing a typevar bound, so inference is
not too willing to deal with it). Try to throw an error in those cases
before those can get allocated and cause problems later from being
non-concrete objects.

Fix #49203
  • Loading branch information
vtjnash committed Apr 7, 2023
1 parent 8baf10e commit a1013e7
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 15 deletions.
10 changes: 8 additions & 2 deletions src/datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -1400,6 +1400,9 @@ JL_DLLEXPORT jl_value_t *jl_new_struct(jl_datatype_t *type, ...)
{
jl_task_t *ct = jl_current_task;
if (type->instance != NULL) return type->instance;
if (!jl_is_datatype(type) || !type->isconcretetype || type->layout == NULL) {
jl_type_error("new", (jl_value_t*)jl_datatype_type, (jl_value_t*)type);
}
va_list args;
size_t i, nf = jl_datatype_nfields(type);
va_start(args, type);
Expand All @@ -1417,7 +1420,7 @@ JL_DLLEXPORT jl_value_t *jl_new_struct(jl_datatype_t *type, ...)
JL_DLLEXPORT jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args, uint32_t na)
{
jl_task_t *ct = jl_current_task;
if (!jl_is_datatype(type) || type->layout == NULL) {
if (!jl_is_datatype(type) || !type->isconcretetype || type->layout == NULL) {
jl_type_error("new", (jl_value_t*)jl_datatype_type, (jl_value_t*)type);
}
size_t nf = jl_datatype_nfields(type);
Expand Down Expand Up @@ -1454,7 +1457,7 @@ JL_DLLEXPORT jl_value_t *jl_new_structt(jl_datatype_t *type, jl_value_t *tup)
jl_task_t *ct = jl_current_task;
if (!jl_is_tuple(tup))
jl_type_error("new", (jl_value_t*)jl_tuple_type, tup);
if (!jl_is_datatype(type) || type->layout == NULL)
if (!jl_is_datatype(type) || !type->isconcretetype || type->layout == NULL)
jl_type_error("new", (jl_value_t *)jl_datatype_type, (jl_value_t *)type);
size_t nargs = jl_nfields(tup);
size_t nf = jl_datatype_nfields(type);
Expand Down Expand Up @@ -1500,6 +1503,9 @@ JL_DLLEXPORT jl_value_t *jl_new_struct_uninit(jl_datatype_t *type)
{
jl_task_t *ct = jl_current_task;
if (type->instance != NULL) return type->instance;
if (!jl_is_datatype(type) || type->layout == NULL) {
jl_type_error("new", (jl_value_t*)jl_datatype_type, (jl_value_t*)type);
}
size_t size = jl_datatype_size(type);
jl_value_t *jv = jl_gc_alloc(ct->ptls, size, type);
if (size > 0)
Expand Down
17 changes: 12 additions & 5 deletions src/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,20 +504,25 @@ static jl_cgval_t generic_bitcast(jl_codectx_t &ctx, const jl_cgval_t *argv)
Type *llvmt = bitstype_to_llvm((jl_value_t*)bt, ctx.builder.getContext(), true);
uint32_t nb = jl_datatype_size(bt);

Value *bt_value_rt = NULL;
if (!jl_is_concrete_type((jl_value_t*)bt)) {
bt_value_rt = boxed(ctx, bt_value);
emit_concretecheck(ctx, bt_value_rt, "bitcast: target type not a leaf primitive type");
}

// Examine the second argument //
bool isboxed;
Type *vxt = julia_type_to_llvm(ctx, v.typ, &isboxed);

if (!jl_is_primitivetype(v.typ) || jl_datatype_size(v.typ) != nb) {
Value *typ = emit_typeof_boxed(ctx, v);
if (!jl_is_primitivetype(v.typ)) {
if (jl_is_datatype(v.typ) && !jl_is_abstracttype(v.typ)) {
emit_error(ctx, "bitcast: expected primitive type value for second argument");
emit_error(ctx, "bitcast: value not a primitive type");
return jl_cgval_t();
}
else {
Value *isprimitive = emit_datatype_isprimitivetype(ctx, typ);
error_unless(ctx, isprimitive, "bitcast: expected primitive type value for second argument");
error_unless(ctx, isprimitive, "bitcast: value not a primitive type");
}
}
if (jl_is_datatype(v.typ) && !jl_is_abstracttype(v.typ)) {
Expand Down Expand Up @@ -570,7 +575,7 @@ static jl_cgval_t generic_bitcast(jl_codectx_t &ctx, const jl_cgval_t *argv)
return mark_julia_type(ctx, vx, false, bt);
}
else {
Value *box = emit_allocobj(ctx, nb, boxed(ctx, bt_value));
Value *box = emit_allocobj(ctx, nb, bt_value_rt);
init_bits_value(ctx, box, vx, ctx.tbaa().tbaa_immut);
return mark_julia_type(ctx, box, true, bt->name->wrapper);
}
Expand Down Expand Up @@ -624,7 +629,9 @@ static jl_cgval_t generic_cast(
return mark_julia_type(ctx, ans, false, jlto);
}
else {
Value *box = emit_allocobj(ctx, nb, boxed(ctx, targ));
Value *targ_rt = boxed(ctx, targ);
emit_concretecheck(ctx, targ_rt, std::string(jl_intrinsic_name(f)) + ": target type not a leaf primitive type");
Value *box = emit_allocobj(ctx, nb, targ_rt);
init_bits_value(ctx, box, ans, ctx.tbaa().tbaa_immut);
return mark_julia_type(ctx, box, true, jlto->name->wrapper);
}
Expand Down
16 changes: 8 additions & 8 deletions src/runtime_intrinsics.c
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ SELECTOR_FUNC(intrinsic_1)
#define un_iintrinsic(name, u) \
JL_DLLEXPORT jl_value_t *jl_##name(jl_value_t *a) \
{ \
return jl_iintrinsic_1(jl_typeof(a), a, #name, u##signbitbyte, jl_intrinsiclambda_ty1, name##_list); \
return jl_iintrinsic_1(a, #name, u##signbitbyte, jl_intrinsiclambda_ty1, name##_list); \
}
#define un_iintrinsic_fast(LLVMOP, OP, name, u) \
un_iintrinsic_ctype(OP, name, 8, u##int##8_t) \
Expand All @@ -743,7 +743,7 @@ SELECTOR_FUNC(intrinsic_u1)
#define uu_iintrinsic(name, u) \
JL_DLLEXPORT jl_value_t *jl_##name(jl_value_t *a) \
{ \
return jl_iintrinsic_1(jl_typeof(a), a, #name, u##signbitbyte, jl_intrinsiclambda_u1, name##_list); \
return jl_iintrinsic_1(a, #name, u##signbitbyte, jl_intrinsiclambda_u1, name##_list); \
}
#define uu_iintrinsic_fast(LLVMOP, OP, name, u) \
uu_iintrinsic_ctype(OP, name, 8, u##int##8_t) \
Expand All @@ -765,14 +765,13 @@ static const select_intrinsic_u1_t name##_list = { \
uu_iintrinsic(name, u)

static inline
jl_value_t *jl_iintrinsic_1(jl_value_t *ty, jl_value_t *a, const char *name,
jl_value_t *jl_iintrinsic_1(jl_value_t *a, const char *name,
char (*getsign)(void*, unsigned),
jl_value_t *(*lambda1)(jl_value_t*, void*, unsigned, unsigned, const void*), const void *list)
{
if (!jl_is_primitivetype(jl_typeof(a)))
jl_errorf("%s: value is not a primitive type", name);
jl_value_t *ty = jl_typeof(a);
if (!jl_is_primitivetype(ty))
jl_errorf("%s: type is not a primitive type", name);
jl_errorf("%s: value is not a primitive type", name);
void *pa = jl_data_ptr(a);
unsigned isize = jl_datatype_size(jl_typeof(a));
unsigned isize2 = next_power_of_two(isize);
Expand Down Expand Up @@ -833,11 +832,12 @@ JL_DLLEXPORT jl_value_t *jl_##name(jl_value_t *ty, jl_value_t *a) \

static inline jl_value_t *jl_intrinsic_cvt(jl_value_t *ty, jl_value_t *a, const char *name, intrinsic_cvt_t op)
{
JL_TYPECHKS(name, datatype, ty);
if (!jl_is_concrete_type(ty) || !jl_is_primitivetype(ty))
jl_errorf("%s: target type not a leaf primitive type", name);
jl_value_t *aty = jl_typeof(a);
if (!jl_is_primitivetype(aty))
jl_errorf("%s: value is not a primitive type", name);
if (!jl_is_primitivetype(ty))
jl_errorf("%s: type is not a primitive type", name);
void *pa = jl_data_ptr(a);
unsigned isize = jl_datatype_size(aty);
unsigned osize = jl_datatype_size(ty);
Expand Down

0 comments on commit a1013e7

Please sign in to comment.