aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2016-04-26 09:11:07 +0200
committerBjörn Gustavsson <[email protected]>2016-04-28 12:13:49 +0200
commita3ec2644f58d8cfeca0240929d44885ff7a517fa (patch)
tree2f0c6a7ffc6ac1ed1aa563a7f6a0a193c5a036f1
parent85ccc38d59dd9751dfd7cead0e4ed0c1e6c169ad (diff)
downloadotp-a3ec2644f58d8cfeca0240929d44885ff7a517fa.tar.gz
otp-a3ec2644f58d8cfeca0240929d44885ff7a517fa.tar.bz2
otp-a3ec2644f58d8cfeca0240929d44885ff7a517fa.zip
v3_core: Don't depend on sys_core_fold for cleaning up
v3_core would generate unsafe code for the following example: f() -> {ok={error,E}} = foo(), E. Internally, the code would look similar to: f() -> Var = foo(), error({badmatch,Var}), E. That is, there would remain a reference to an unbound variable. Normally, sys_core_fold would remove the reference to 'E', but if if optimization was disabled the compiler would crash.
-rw-r--r--lib/compiler/src/v3_core.erl23
-rw-r--r--lib/compiler/test/match_SUITE.erl7
2 files changed, 25 insertions, 5 deletions
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 3299149457..83b3650180 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -510,8 +510,16 @@ unforce(_, Vs) -> Vs.
exprs([E0|Es0], St0) ->
{E1,Eps,St1} = expr(E0, St0),
- {Es1,St2} = exprs(Es0, St1),
- {Eps ++ [E1] ++ Es1,St2};
+ case E1 of
+ #iprimop{name=#c_literal{val=match_fail}} ->
+ %% Must discard the rest of the body, because it
+ %% may refer to variables that have not been bound.
+ %% Example: {ok={error,E}} = foo(), E.
+ {Eps ++ [E1],St1};
+ _ ->
+ {Es1,St2} = exprs(Es0, St1),
+ {Eps ++ [E1] ++ Es1,St2}
+ end;
exprs([], St) -> {[],St}.
%% expr(Expr, State) -> {Cexpr,[PreExp],State}.
@@ -681,9 +689,14 @@ expr({match,L,P0,E0}, St0) ->
Fc = fail_clause([Fpat], Lanno, c_tuple([#c_literal{val=badmatch},Fpat])),
case P2 of
nomatch ->
- St = add_warning(L, nomatch, St5),
- {#icase{anno=#a{anno=Lanno},
- args=[E2],clauses=[],fc=Fc},Eps1++Eps2,St};
+ St6 = add_warning(L, nomatch, St5),
+ {Expr,Eps3,St} = safe(E1, St6),
+ Eps = Eps1 ++ Eps2 ++ Eps3,
+ Badmatch = c_tuple([#c_literal{val=badmatch},Expr]),
+ Fail = #iprimop{anno=#a{anno=Lanno},
+ name=#c_literal{val=match_fail},
+ args=[Badmatch]},
+ {Fail,Eps,St};
Other when not is_atom(Other) ->
{#imatch{anno=#a{anno=Lanno},pat=P2,arg=E2,fc=Fc},Eps1++Eps2,St5}
end;
diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl
index 45d84a7b80..92a9802cad 100644
--- a/lib/compiler/test/match_SUITE.erl
+++ b/lib/compiler/test/match_SUITE.erl
@@ -150,6 +150,9 @@ aliases(Config) when is_list(Config) ->
none = mixed_aliases({a,42}),
none = mixed_aliases(42),
+ %% Non-matching aliases.
+ {'EXIT',{{badmatch,42},_}} = (catch nomatch_alias(42)),
+
ok.
str_alias(V) ->
@@ -259,6 +262,10 @@ mixed_aliases(<<X:8>> = {a,X}) -> {c,X};
mixed_aliases([X] = <<X:8>>) -> {d,X};
mixed_aliases(_) -> none.
+nomatch_alias(I) ->
+ {ok={A,B}} = id(I),
+ {A,B}.
+
%% OTP-7018.
match_in_call(Config) when is_list(Config) ->