diff options
author | Björn Gustavsson <[email protected]> | 2016-04-26 09:11:07 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2016-04-28 12:13:49 +0200 |
commit | a3ec2644f58d8cfeca0240929d44885ff7a517fa (patch) | |
tree | 2f0c6a7ffc6ac1ed1aa563a7f6a0a193c5a036f1 | |
parent | 85ccc38d59dd9751dfd7cead0e4ed0c1e6c169ad (diff) | |
download | otp-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.erl | 23 | ||||
-rw-r--r-- | lib/compiler/test/match_SUITE.erl | 7 |
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) -> |