diff options
author | Björn Gustavsson <[email protected]> | 2018-02-09 10:37:48 +0100 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2018-02-12 13:31:27 +0100 |
commit | a48ec9a2750260845f035c2e968244cb5cd33a3d (patch) | |
tree | 9a44bfd630ad11aa5ac03a8b273ccbc796704672 /lib/compiler/src/beam_block.erl | |
parent | cd9b6371a13c37f8f82586fcd82f212d306d8fad (diff) | |
download | otp-a48ec9a2750260845f035c2e968244cb5cd33a3d.tar.gz otp-a48ec9a2750260845f035c2e968244cb5cd33a3d.tar.bz2 otp-a48ec9a2750260845f035c2e968244cb5cd33a3d.zip |
Fix unsafe use of 'allocate' where 'allocate_zero' should be used
The more aggressive optimizations of 'allocate_zero' introduced
in cb6fc15c35c7e could produce unsafe code such as the following:
{allocate,0,1}.
{bif,element,{f,0},[{integer,1},{x,0}],{x,0}}.
The code is not safe because if element/2 fails, the runtime
system may scan the stack and find garbage that looks like a
catch tag, and would most probably crash.
Fix the problem by making beam_utils:is_killed/3 be more conservative
when asked whether a Y register will be killed.
Also fix an unsafe move upwards of an allocation instruction
in beam_block.
Diffstat (limited to 'lib/compiler/src/beam_block.erl')
-rw-r--r-- | lib/compiler/src/beam_block.erl | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl index 9543aa1355..7183381334 100644 --- a/lib/compiler/src/beam_block.erl +++ b/lib/compiler/src/beam_block.erl @@ -206,7 +206,7 @@ move_allocates([]) -> []. move_allocates_1([{'%anno',_}|Is], Acc) -> move_allocates_1(Is, Acc); -move_allocates_1([I|Is], [{set,[],[],{alloc,Live0,Info}}|Acc]=Acc0) -> +move_allocates_1([I|Is], [{set,[],[],{alloc,Live0,Info0}}|Acc]=Acc0) -> case alloc_may_pass(I) of false -> move_allocates_1(Is, [I|Acc0]); @@ -215,6 +215,7 @@ move_allocates_1([I|Is], [{set,[],[],{alloc,Live0,Info}}|Acc]=Acc0) -> not_possible -> move_allocates_1(Is, [I|Acc0]); Live when is_integer(Live) -> + Info = safe_info(Info0), A = {set,[],[],{alloc,Live,Info}}, move_allocates_1(Is, [A,I|Acc]) end @@ -230,6 +231,13 @@ alloc_may_pass({set,_,_,put_list}) -> false; alloc_may_pass({set,_,_,put}) -> false; alloc_may_pass({set,_,_,_}) -> true. +safe_info({nozero,Stack,Heap,_}) -> + %% nozero is not safe if the allocation instruction is moved + %% upwards past an instruction that may throw an exception + %% (such as element/2). + {zero,Stack,Heap,[]}; +safe_info(Info) -> Info. + %% opt([Instruction]) -> [Instruction] %% Optimize the instruction stream inside a basic block. |