From a1013e7022bc0c56bc46cb737efee790a73b1a92 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 7 Apr 2023 13:25:31 -0400 Subject: [PATCH] more robust validation of allocation type (#49269) 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 --- src/datatype.c | 10 ++++++++-- src/intrinsics.cpp | 17 ++++++++++++----- src/runtime_intrinsics.c | 16 ++++++++-------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/datatype.c b/src/datatype.c index 91fd24495f299..894beeaa1b7e6 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -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); @@ -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); @@ -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); @@ -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) diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index e829eea7f625a..8f2f2273506b4 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -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)) { @@ -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); } @@ -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); } diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index 99a81974a68b3..d53eb368de495 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -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) \ @@ -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) \ @@ -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); @@ -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);