aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2016-09-13 12:35:24 +0200
committerBjörn Gustavsson <[email protected]>2016-09-13 13:27:28 +0200
commit81c5e15544679baeeb8c18b72156b79aa4badebb (patch)
tree349fc1c561856341e6406306e411b4aa5a6705fe
parentec56f41f7a48055896037ac77927b99202371e62 (diff)
downloadotp-81c5e15544679baeeb8c18b72156b79aa4badebb.tar.gz
otp-81c5e15544679baeeb8c18b72156b79aa4badebb.tar.bz2
otp-81c5e15544679baeeb8c18b72156b79aa4badebb.zip
beam_validator: Handle unreachable instructions
ab03678e introduced an optimization in the beam_z pass that could introduce unreachable code in BEAM files (a 'jump' instruction is removed after a 'raise' instruction, but the code following the target of the 'jump' is not removed). Since this situation happens very rarely, there is no point in adding another pass that can remove unreachable code after beam_z. Instead we will make sure that beam_validator can skip the unreachable code. Skipping unreachable code is already done in valfun_1/2 (for historical reasons), but we will also need to do it in val_dsetel/2.
-rw-r--r--lib/compiler/src/beam_validator.erl4
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl25
2 files changed, 26 insertions, 3 deletions
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 4c0cb6780a..16dba35adc 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -808,9 +808,11 @@ validate_bs_skip_utf(Fail, Ctx, Live, Vst0) ->
%% A possibility for garbage collection must not occur between setelement/3 and
%% set_tuple_element/3.
%%
+%% Note that #vst.current will be 'none' if the instruction is unreachable.
+%%
val_dsetel({move,_,_}, Vst) ->
Vst;
-val_dsetel({call_ext,3,{extfunc,erlang,setelement,3}}, #vst{current=St}=Vst) ->
+val_dsetel({call_ext,3,{extfunc,erlang,setelement,3}}, #vst{current=#st{}=St}=Vst) ->
Vst#vst{current=St#st{setelem=true}};
val_dsetel({set_tuple_element,_,_,_}, #vst{current=#st{setelem=false}}) ->
error(illegal_context_for_set_tuple_element);
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index 263fd2ca7e..ca85eef688 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -32,7 +32,8 @@
bad_bin_match/1,bad_dsetel/1,
state_after_fault_in_catch/1,no_exception_in_catch/1,
undef_label/1,illegal_instruction/1,failing_gc_guard_bif/1,
- map_field_lists/1,cover_bin_opt/1]).
+ map_field_lists/1,cover_bin_opt/1,
+ val_dsetel/1]).
-include_lib("common_test/include/ct.hrl").
@@ -60,7 +61,7 @@ groups() ->
freg_state,bad_bin_match,bad_dsetel,
state_after_fault_in_catch,no_exception_in_catch,
undef_label,illegal_instruction,failing_gc_guard_bif,
- map_field_lists,cover_bin_opt]}].
+ map_field_lists,cover_bin_opt,val_dsetel]}].
init_per_suite(Config) ->
Config.
@@ -546,3 +547,23 @@ beam_val(M) ->
_ = [io:put_chars(beam_validator:format_error(E)) ||
E <- Errors],
Errors.
+
+%%%-------------------------------------------------------------------------
+
+val_dsetel(_Config) ->
+ self() ! 13,
+ {'EXIT',{{try_clause,participating},_}} = (catch night(0)),
+ ok.
+
+night(Turned) ->
+ receive
+ 13 ->
+ try participating of engine -> 16 after false end
+ end,
+ %% The setelement/3 call is unreachable.
+ Turned(setelement(#{true => Turned},
+ participating(Turned, "suit", 40, []),
+ Turned < Turned)),
+ ok.
+
+participating(_, _, _, _) -> ok.