aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src/beam_ssa_codegen.erl
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2019-08-01 18:42:09 +0200
committerBjörn Gustavsson <[email protected]>2019-08-05 13:00:46 +0200
commite6c818956cadeb90f62f61ee5263ba4035be40c4 (patch)
treec6922ece2ea18fac10bd767b10384f204214a1b5 /lib/compiler/src/beam_ssa_codegen.erl
parent3967d28c05dae77db30b15e56eb4ececf4f1afef (diff)
downloadotp-e6c818956cadeb90f62f61ee5263ba4035be40c4.tar.gz
otp-e6c818956cadeb90f62f61ee5263ba4035be40c4.tar.bz2
otp-e6c818956cadeb90f62f61ee5263ba4035be40c4.zip
Ensure that the stack slots are initialized when matching maps
When matching a map, the compiler could fail to generate code that would initialize all stack slots (Y registers) properly. Here is a general outline of code that *could* cause this problem: foo(Key, Map) -> Res = case Map of #{Key := Val} -> %% Do something with Val here. . . . #{} -> [] end, %% The stack slot for Val might not have been initialized %% here if the key was not present in the map. . . . %% Use Res. . . . The code generator would wrongly assume that the map matching would always initialize the stack slot, and if nothing else happened to force that stack slot to be initialized, it would remain uninitialized, which would likely crash the runtime system at the next garbage collection. `beam_validator` is supposed to find these kind of problems, but a bug in `beam_validator` prevented it from detecting this problem. https://bugs.erlang.org/browse/ERL-1017
Diffstat (limited to 'lib/compiler/src/beam_ssa_codegen.erl')
-rw-r--r--lib/compiler/src/beam_ssa_codegen.erl18
1 files changed, 14 insertions, 4 deletions
diff --git a/lib/compiler/src/beam_ssa_codegen.erl b/lib/compiler/src/beam_ssa_codegen.erl
index 07f4c8b461..08641e2abc 100644
--- a/lib/compiler/src/beam_ssa_codegen.erl
+++ b/lib/compiler/src/beam_ssa_codegen.erl
@@ -764,9 +764,8 @@ defined(Linear, #cg{regs=Regs}) ->
def([{L,#cg_blk{is=Is0,last=Last}=Blk0}|Bs], DefMap0, Regs) ->
Def0 = def_get(L, DefMap0),
- {Is,Def} = def_is(Is0, Regs, Def0, []),
- Successors = successors(Last),
- DefMap = def_successors(Successors, Def, DefMap0),
+ {Is,Def,MaybeDef} = def_is(Is0, Regs, Def0, []),
+ DefMap = def_successors(Last, Def, MaybeDef, DefMap0),
Blk = Blk0#cg_blk{is=Is},
[{L,Blk}|def(Bs, DefMap, Regs)];
def([], _, _) -> [].
@@ -780,6 +779,11 @@ def_get(L, DefMap) ->
def_is([#cg_alloc{anno=Anno0}=I0|Is], Regs, Def, Acc) ->
I = I0#cg_alloc{anno=Anno0#{def_yregs=>Def}},
def_is(Is, Regs, Def, [I|Acc]);
+def_is([#cg_set{op=succeeded,args=[Var]}=I], Regs, Def, Acc) ->
+ %% Var will only be defined on the success branch of the `br`
+ %% for this block.
+ MaybeDef = def_add_yreg(Var, [], Regs),
+ {reverse(Acc, [I]),Def,MaybeDef};
def_is([#cg_set{op=kill_try_tag,args=[#b_var{}=Tag]}=I|Is], Regs, Def0, Acc) ->
Def = ordsets:del_element(Tag, Def0),
def_is(Is, Regs, Def, [I|Acc]);
@@ -822,7 +826,7 @@ def_is([#cg_set{anno=Anno0,dst=Dst}=I0|Is], Regs, Def0, Acc) ->
Def = def_add_yreg(Dst, Def0, Regs),
def_is(Is, Regs, Def, [I|Acc]);
def_is([], _, Def, Acc) ->
- {reverse(Acc),Def}.
+ {reverse(Acc),Def,[]}.
def_add_yreg(Dst, Def, Regs) ->
case is_yreg(Dst, Regs) of
@@ -830,6 +834,12 @@ def_add_yreg(Dst, Def, Regs) ->
false -> Def
end.
+def_successors(#cg_br{bool=#b_var{},succ=Succ,fail=Fail}, Def, MaybeDef, DefMap0) ->
+ DefMap = def_successors([Fail], ordsets:subtract(Def, MaybeDef), DefMap0),
+ def_successors([Succ], Def, DefMap);
+def_successors(Last, Def, [], DefMap) ->
+ def_successors(successors(Last), Def, DefMap).
+
def_successors([S|Ss], Def0, DefMap) ->
case DefMap of
#{S:=Def1} ->