aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler/src/beam_utils.erl
diff options
context:
space:
mode:
authorBjörn Gustavsson <bjorn@erlang.org>2010-11-26 09:22:44 +0100
committerBjörn Gustavsson <bjorn@erlang.org>2010-11-26 10:25:07 +0100
commit8836ebccae92886decf5645944ae4ce8a2f99947 (patch)
tree797dfafe3ca5173d9ffb5bfba68bb2fe7959062a /lib/compiler/src/beam_utils.erl
parent99a28d961d2d760e98353b55991f1fc51dee06b0 (diff)
downloadotp-8836ebccae92886decf5645944ae4ce8a2f99947.tar.gz
otp-8836ebccae92886decf5645944ae4ce8a2f99947.tar.bz2
otp-8836ebccae92886decf5645944ae4ce8a2f99947.zip
beam_utils: Fix liveness analysis for gc_bif instructions
When gc_bif instructions occurred outside of a block, beam_utils:check_liveness/3 did not take into account that the instruction could do a garbage collection, and could falsely report that an x register would be killed. That could cause the beam_dead pass to make the code unsafe by removing the assignment to an x register that would subsequently be referenced by the garbage collector. Reported-by: Christopher Williams
Diffstat (limited to 'lib/compiler/src/beam_utils.erl')
-rw-r--r--lib/compiler/src/beam_utils.erl27
1 files changed, 17 insertions, 10 deletions
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index 761d4ffec0..dc8079d0b7 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -407,16 +407,23 @@ check_liveness(R, [{bif,Op,{f,Fail},Ss,D}|Is], St0) ->
Other ->
Other
end;
-check_liveness(R, [{gc_bif,Op,{f,Fail},_,Ss,D}|Is], St0) ->
- case check_liveness_fail(R, Op, Ss, Fail, St0) of
- {killed,St} = Killed ->
- case member(R, Ss) of
- true -> {used,St};
- false when R =:= D -> Killed;
- false -> check_liveness(R, Is, St)
- end;
- Other ->
- Other
+check_liveness(R, [{gc_bif,Op,{f,Fail},Live,Ss,D}|Is], St0) ->
+ case R of
+ {x,X} when X >= Live ->
+ {killed,St0};
+ {x,_} ->
+ {used,St0};
+ _ ->
+ case check_liveness_fail(R, Op, Ss, Fail, St0) of
+ {killed,St}=Killed ->
+ case member(R, Ss) of
+ true -> {used,St};
+ false when R =:= D -> Killed;
+ false -> check_liveness(R, Is, St)
+ end;
+ Other ->
+ Other
+ end
end;
check_liveness(R, [{bs_add,{f,0},Ss,D}|Is], St) ->
case member(R, Ss) of