File 0221-Fix-unsafe-code-generation-for-binary-matching.patch of Package erlang
From 60f8f9eaa7966258126d0c9a4fff1514cbfa0830 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Thu, 27 Jun 2024 12:00:23 +0200
Subject: [PATCH] Fix unsafe code generation for binary matching
The common sub expression (CSE) optimization could cause a call to a
guard BIF to be inserted into the middle of a sequence of binary
syntax matching instructions, which in turn could cause unsafe
`bs_match` (BEAM) instructions to be emitted.
Resolves #8617
---
lib/compiler/src/beam_ssa_opt.erl | 39 +++++++++++++++++---------
lib/compiler/test/bs_bincomp_SUITE.erl | 11 ++++++++
2 files changed, 37 insertions(+), 13 deletions(-)
diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl
index fca1e08877..cb81f59768 100644
--- a/lib/compiler/src/beam_ssa_opt.erl
+++ b/lib/compiler/src/beam_ssa_opt.erl
@@ -3623,7 +3623,7 @@ is_bs_match_blk(L, Blocks) ->
Blk = map_get(L, Blocks),
case Blk of
#b_blk{is=Is,last=#b_br{bool=#b_var{}}=Last} ->
- case is_bs_match_is(Is) of
+ case is_bs_match_is(Is, true) of
no ->
no;
{yes,CtxSizeUnit} ->
@@ -3634,20 +3634,33 @@ is_bs_match_blk(L, Blocks) ->
end.
is_bs_match_is([#b_set{op=bs_match,dst=Dst}=I,
- #b_set{op={succeeded,guard},args=[Dst]}]) ->
- case is_viable_match(I) of
- no ->
+ #b_set{op={succeeded,guard},args=[Dst]}], Safe) ->
+ case Safe of
+ false ->
+ %% This `bs_match` (SSA) instruction was preceded by other
+ %% instructions (such as guard BIF calls) that would
+ %% prevent this match operation to be incorporated into
+ %% the commands list of a `bs_match` (BEAM) instruction.
no;
- {yes,{Ctx,Size,Unit}} when Size bsr 24 =:= 0 ->
- %% Only include matches of reasonable size.
- {yes,{{Ctx,Dst},Size,Unit}};
- {yes,_} ->
- %% Too large size.
- no
+ true ->
+ case is_viable_match(I) of
+ no ->
+ no;
+ {yes,{Ctx,Size,Unit}} when Size bsr 24 =:= 0 ->
+ %% Only include matches of reasonable size.
+ {yes,{{Ctx,Dst},Size,Unit}};
+ {yes,_} ->
+ %% Too large size.
+ no
+ end
end;
-is_bs_match_is([_|Is]) ->
- is_bs_match_is(Is);
-is_bs_match_is([]) -> no.
+is_bs_match_is([#b_set{op=bs_extract}|Is], Safe) ->
+ is_bs_match_is(Is, Safe);
+is_bs_match_is([#b_set{op=bs_start_match}|Is], _Safe) ->
+ is_bs_match_is(Is, true);
+is_bs_match_is([_|Is], _Safe) ->
+ is_bs_match_is(Is, false);
+is_bs_match_is([], _Safe) -> no.
is_viable_match(#b_set{op=bs_match,args=Args}) ->
case Args of
diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl
index 3d95ec29d8..e5cd824ed0 100644
--- a/lib/compiler/test/bs_bincomp_SUITE.erl
+++ b/lib/compiler/test/bs_bincomp_SUITE.erl
@@ -671,12 +671,23 @@ grab_bag(_Config) ->
%% Cover a line v3_kernel:get_line/1.
_ = catch << ok || <<>> <= ok, ok >>,
+ [] = grab_bag_gh_8617(<<>>),
+ [0] = grab_bag_gh_8617(<<1:1>>),
+ [0,0,0] = grab_bag_gh_8617(<<0:3>>),
+
ok.
grab_bag_gh_6553(<<X>>) ->
%% Would crash in beam_ssa_pre_codegen.
<<X, ((<<_:0>> = <<_>>) = <<>>)>>.
+grab_bag_gh_8617(Bin) ->
+ %% GH-8617: CSE would cause a call self/0 to be inserted in
+ %% the middle of a sequence of `bs_match` instructions, causing
+ %% unsafe matching code to be emitted.
+ [0 || <<_:0, _:(tuple_size({self()}))>> <= Bin,
+ is_pid(id(self()))].
+
cs_init() ->
erts_debug:set_internal_state(available_internal_state, true),
ok.
--
2.35.3