aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Högberg <[email protected]>2019-01-28 14:24:51 +0100
committerJohn Högberg <[email protected]>2019-01-28 15:33:01 +0100
commitd051dc894753089c8a912814957258ddab733670 (patch)
treea417073000231156c9c40e6c43c4f78d01c08e83
parente026dd28a850a2ce2b95207515b1bc5cb2bb0d50 (diff)
downloadotp-d051dc894753089c8a912814957258ddab733670.tar.gz
otp-d051dc894753089c8a912814957258ddab733670.tar.bz2
otp-d051dc894753089c8a912814957258ddab733670.zip
beam_validator: Add explicit assertions for fragile terms
We haven't seen any related bugs so far, but all instructions that place a term in another ought to reject fragile inputs. It can't hurt to check.
-rw-r--r--lib/compiler/src/beam_validator.erl60
1 files changed, 33 insertions, 27 deletions
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index c99fc47c24..b56d53d4ce 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -303,11 +303,11 @@ valfun_1(_I, #vst{current=none}=Vst) ->
%% the original R10B compiler thought would return.
Vst;
valfun_1({badmatch,Src}, Vst) ->
- assert_term(Src, Vst),
+ assert_not_fragile(Src, Vst),
verify_y_init(Vst),
kill_state(Vst);
valfun_1({case_end,Src}, Vst) ->
- assert_term(Src, Vst),
+ assert_not_fragile(Src, Vst),
verify_y_init(Vst),
kill_state(Vst);
valfun_1(if_end, Vst) ->
@@ -315,7 +315,7 @@ valfun_1(if_end, Vst) ->
kill_state(Vst);
valfun_1({try_case_end,Src}, Vst) ->
verify_y_init(Vst),
- assert_term(Src, Vst),
+ assert_not_fragile(Src, Vst),
kill_state(Vst);
%% Instructions that cannot cause exceptions
valfun_1({bs_get_tail,Ctx,Dst,Live}, Vst0) ->
@@ -359,12 +359,12 @@ valfun_1({bif,Op,{f,_},Src,Dst}=I, Vst) ->
end;
%% Put instructions.
valfun_1({put_list,A,B,Dst}, Vst0) ->
- assert_term(A, Vst0),
- assert_term(B, Vst0),
+ assert_not_fragile(A, Vst0),
+ assert_not_fragile(B, Vst0),
Vst = eat_heap(2, Vst0),
create_term(cons, Dst, Vst);
valfun_1({put_tuple2,Dst,{list,Elements}}, Vst0) ->
- _ = [assert_term(El, Vst0) || El <- Elements],
+ _ = [assert_not_fragile(El, Vst0) || El <- Elements],
Size = length(Elements),
Vst = eat_heap(Size+1, Vst0),
Type = {tuple,Size},
@@ -376,7 +376,7 @@ valfun_1({put_tuple,Sz,Dst}, Vst0) when is_integer(Sz) ->
St = St0#st{puts_left={Sz,{Dst,{tuple,Sz}}}},
Vst#vst{current=St};
valfun_1({put,Src}, Vst0) ->
- assert_term(Src, Vst0),
+ assert_not_fragile(Src, Vst0),
Vst = eat_heap(1, Vst0),
#vst{current=St0} = Vst,
case St0 of
@@ -646,7 +646,7 @@ valfun_4({gc_bif,Op,{f,Fail},Live,Ss,Dst}, #vst{current=St0}=Vst0) ->
Vst = prune_x_regs(Live, Vst3),
extract_term(Type, Ss, Dst, Vst, Vst0);
valfun_4(return, #vst{current=#st{numy=none}}=Vst) ->
- assert_term({x,0}, Vst),
+ assert_not_fragile({x,0}, Vst),
kill_state(Vst);
valfun_4(return, #vst{current=#st{numy=NumY}}) ->
error({stack_frame,NumY});
@@ -672,7 +672,7 @@ valfun_4(timeout, #vst{current=St}=Vst) ->
valfun_4(send, Vst) ->
call(send, 2, Vst);
valfun_4({set_tuple_element,Src,Tuple,I}, Vst) ->
- assert_term(Src, Vst),
+ assert_not_fragile(Src, Vst),
assert_type({tuple_element,I+1}, Tuple, Vst),
Vst;
%% Match instructions.
@@ -795,8 +795,8 @@ valfun_4({test,_Op,{f,Lbl},Src}, Vst) ->
validate_src(Src, Vst),
branch_state(Lbl, Vst);
valfun_4({bs_add,{f,Fail},[A,B,_],Dst}, Vst) ->
- assert_term(A, Vst),
- assert_term(B, Vst),
+ assert_not_fragile(A, Vst),
+ assert_not_fragile(B, Vst),
create_term({integer,[]}, Dst, branch_state(Fail, Vst));
valfun_4({bs_utf8_size,{f,Fail},A,Dst}, Vst) ->
assert_term(A, Vst),
@@ -811,7 +811,7 @@ valfun_4({bs_init2,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) ->
is_integer(Sz) ->
ok;
true ->
- assert_term(Sz, Vst0)
+ assert_not_fragile(Sz, Vst0)
end,
Vst1 = heap_alloc(Heap, Vst0),
Vst2 = branch_state(Fail, Vst1),
@@ -833,39 +833,39 @@ valfun_4({bs_init_bits,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) ->
valfun_4({bs_append,{f,Fail},Bits,Heap,Live,_Unit,Bin,_Flags,Dst}, Vst0) ->
verify_live(Live, Vst0),
verify_y_init(Vst0),
- assert_term(Bits, Vst0),
- assert_term(Bin, Vst0),
+ assert_not_fragile(Bits, Vst0),
+ assert_not_fragile(Bin, Vst0),
Vst1 = heap_alloc(Heap, Vst0),
Vst2 = branch_state(Fail, Vst1),
Vst = prune_x_regs(Live, Vst2),
create_term(binary, Dst, Vst);
valfun_4({bs_private_append,{f,Fail},Bits,_Unit,Bin,_Flags,Dst}, Vst0) ->
- assert_term(Bits, Vst0),
- assert_term(Bin, Vst0),
+ assert_not_fragile(Bits, Vst0),
+ assert_not_fragile(Bin, Vst0),
Vst = branch_state(Fail, Vst0),
create_term(binary, Dst, Vst);
valfun_4({bs_put_string,Sz,_}, Vst) when is_integer(Sz) ->
Vst;
valfun_4({bs_put_binary,{f,Fail},Sz,_,_,Src}, Vst) ->
- assert_term(Sz, Vst),
- assert_term(Src, Vst),
+ assert_not_fragile(Sz, Vst),
+ assert_not_fragile(Src, Vst),
branch_state(Fail, Vst);
valfun_4({bs_put_float,{f,Fail},Sz,_,_,Src}, Vst) ->
- assert_term(Sz, Vst),
- assert_term(Src, Vst),
+ assert_not_fragile(Sz, Vst),
+ assert_not_fragile(Src, Vst),
branch_state(Fail, Vst);
valfun_4({bs_put_integer,{f,Fail},Sz,_,_,Src}, Vst) ->
- assert_term(Sz, Vst),
- assert_term(Src, Vst),
+ assert_not_fragile(Sz, Vst),
+ assert_not_fragile(Src, Vst),
branch_state(Fail, Vst);
valfun_4({bs_put_utf8,{f,Fail},_,Src}, Vst) ->
- assert_term(Src, Vst),
+ assert_not_fragile(Src, Vst),
branch_state(Fail, Vst);
valfun_4({bs_put_utf16,{f,Fail},_,Src}, Vst) ->
- assert_term(Src, Vst),
+ assert_not_fragile(Src, Vst),
branch_state(Fail, Vst);
valfun_4({bs_put_utf32,{f,Fail},_,Src}, Vst) ->
- assert_term(Src, Vst),
+ assert_not_fragile(Src, Vst),
branch_state(Fail, Vst);
%% Map instructions.
valfun_4({put_map_assoc,{f,Fail},Src,Dst,Live,{list,List}}, Vst) ->
@@ -909,7 +909,7 @@ verify_put_map(Fail, Src, Dst, Live, List, Vst0) ->
assert_type(map, Src, Vst0),
verify_live(Live, Vst0),
verify_y_init(Vst0),
- foreach(fun (Term) -> assert_term(Term, Vst0) end, List),
+ foreach(fun (Term) -> assert_not_fragile(Term, Vst0) end, List),
Vst1 = heap_alloc(0, Vst0),
Vst2 = branch_state(Fail, Vst1),
Vst = prune_x_regs(Live, Vst2),
@@ -1015,7 +1015,7 @@ verify_call_args(_, Live, _) ->
verify_call_args_1(0, _) -> ok;
verify_call_args_1(N, Vst) ->
X = N - 1,
- get_term_type({x,X}, Vst),
+ assert_not_fragile({x,X}, Vst),
verify_call_args_1(X, Vst).
verify_local_call(Lbl, Live, Vst) ->
@@ -1545,6 +1545,12 @@ assert_term(Src, Vst) ->
get_term_type(Src, Vst),
ok.
+assert_not_fragile(Src, Vst) ->
+ case get_term_type(Src, Vst) of
+ {fragile, _} -> error({fragile_message_reference, Src});
+ _ -> ok
+ end.
+
assert_not_literal({x,_}) -> ok;
assert_not_literal({y,_}) -> ok;
assert_not_literal(Literal) -> error({literal_not_allowed,Literal}).