Skip to content

Commit 9f61878

Browse files
yuyichaovtjnash
authored andcommitted
Make sure error from Expr(:new) is not optimized away. (#23353)
* Fix effect_free for `Expr(:new)` Check if the type being constructed is leaftype and check if all fields are correctly typed. The expression could throw an error otherwise. * Fix functions used by interpreter and codegen to check field types * Fix (remove) assumption of `Expr(:new)` being effect free in lowering
1 parent fc6b0ef commit 9f61878

File tree

5 files changed

+55
-11
lines changed

5 files changed

+55
-11
lines changed

base/inference.jl

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3925,12 +3925,19 @@ function effect_free(@nospecialize(e), src::CodeInfo, mod::Module, allow_volatil
39253925
return false
39263926
end
39273927
elseif head === :new
3928-
if !allow_volatile
3929-
a = ea[1]
3930-
typ = widenconst(exprtype(a, src, mod))
3931-
if !isType(typ) || !isa((typ::Type).parameters[1],DataType) || ((typ::Type).parameters[1]::DataType).mutable
3932-
return false
3933-
end
3928+
a = ea[1]
3929+
typ = exprtype(a, src, mod)
3930+
# `Expr(:new)` of unknown type could raise arbitrary TypeError.
3931+
typ, isexact = instanceof_tfunc(typ)
3932+
isexact || return false
3933+
(isleaftype(typ) && !iskindtype(typ)) || return false
3934+
typ = typ::DataType
3935+
if !allow_volatile && typ.mutable
3936+
return false
3937+
end
3938+
fieldcount(typ) >= length(ea) - 1 || return false
3939+
for fld_idx in 1:(length(ea) - 1)
3940+
exprtype(ea[fld_idx + 1], src, mod) fieldtype(typ, fld_idx) || return false
39343941
end
39353942
# fall-through
39363943
elseif head === :return

src/datatype.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ JL_DLLEXPORT jl_value_t *jl_new_struct(jl_datatype_t *type, ...)
717717
size_t nf = jl_datatype_nfields(type);
718718
va_start(args, type);
719719
jl_value_t *jv = jl_gc_alloc(ptls, jl_datatype_size(type), type);
720-
for(size_t i=0; i < nf; i++) {
720+
for (size_t i = 0; i < nf; i++) {
721721
jl_set_nth_field(jv, i, va_arg(args, jl_value_t*));
722722
}
723723
va_end(args);
@@ -731,7 +731,10 @@ JL_DLLEXPORT jl_value_t *jl_new_structv(jl_datatype_t *type, jl_value_t **args,
731731
if (type->instance != NULL) return type->instance;
732732
size_t nf = jl_datatype_nfields(type);
733733
jl_value_t *jv = jl_gc_alloc(ptls, jl_datatype_size(type), type);
734-
for(size_t i=0; i < na; i++) {
734+
for (size_t i = 0; i < na; i++) {
735+
jl_value_t *ft = jl_field_type(type, i);
736+
if (!jl_isa(args[i], ft))
737+
jl_type_error("new", ft, args[i]);
735738
jl_set_nth_field(jv, i, args[i]);
736739
}
737740
for(size_t i=na; i < nf; i++) {

src/interpreter.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,12 @@ static jl_value_t *eval(jl_value_t *e, interpreter_state *s)
270270
JL_GC_PUSH2(&thetype, &v);
271271
assert(jl_is_structtype(thetype));
272272
v = jl_new_struct_uninit((jl_datatype_t*)thetype);
273-
for(size_t i=1; i < nargs; i++) {
274-
jl_set_nth_field(v, i-1, eval(args[i], s));
273+
for (size_t i = 1; i < nargs; i++) {
274+
jl_value_t *ft = jl_field_type(thetype, i - 1);
275+
jl_value_t *fldv = eval(args[i], s);
276+
if (!jl_isa(fldv, ft))
277+
jl_type_error("new", ft, fldv);
278+
jl_set_nth_field(v, i - 1, fldv);
275279
}
276280
JL_GC_POP();
277281
return v;

src/julia-syntax.scm

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3507,7 +3507,6 @@ f(x) = yt(x)
35073507
(callex (cons (car e) args)))
35083508
(cond (tail (emit-return callex))
35093509
(value callex)
3510-
((eq? (car e) 'new) #f)
35113510
(else (emit callex)))))
35123511
((=)
35133512
(let* ((rhs (compile (caddr e) break-labels #t #f))

test/core.jl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3147,6 +3147,37 @@ end
31473147
@test_throws TypeError MyType8010([3.0;4.0])
31483148
@test_throws TypeError MyType8010_ghost([3.0;4.0])
31493149

3150+
module TestNewTypeError
3151+
using Base.Test
3152+
3153+
struct A
3154+
end
3155+
struct B
3156+
a::A
3157+
end
3158+
@eval function f1()
3159+
# Emitting this direction is not recommended but it can come from `convert` that does not
3160+
# return the correct type.
3161+
$(Expr(:new, B, 1))
3162+
end
3163+
@eval function f2()
3164+
a = $(Expr(:new, B, 1))
3165+
a = a
3166+
return nothing
3167+
end
3168+
@generated function f3()
3169+
quote
3170+
$(Expr(:new, B, 1))
3171+
return nothing
3172+
end
3173+
end
3174+
@test_throws TypeError f1()
3175+
@test_throws TypeError f2()
3176+
@test_throws TypeError f3()
3177+
@test_throws TypeError eval(Expr(:new, B, 1))
3178+
3179+
end
3180+
31503181
# don't allow redefining types if ninitialized changes
31513182
struct NInitializedTestType
31523183
a

0 commit comments

Comments
 (0)