File 2662-Fix-unsafe-binary-optimization.patch of Package erlang
From 04a5cf70838f393387735e17c9ca3cd126701000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Thu, 19 Mar 2026 09:43:23 +0100
Subject: [PATCH] Fix unsafe binary optimization
The optimization introduced in 7318e9cbea60f8 could sometimes rewrite
matching of a binary segment to matching of an integer segment.
Resolves #10878
---
lib/compiler/src/beam_core_to_ssa.erl | 12 ++++++---
lib/compiler/test/bs_match_SUITE.erl | 35 +++++++++++++++++++++++++--
2 files changed, 41 insertions(+), 6 deletions(-)
diff --git a/lib/compiler/src/beam_core_to_ssa.erl b/lib/compiler/src/beam_core_to_ssa.erl
index 8d0bf840f9..fa9725a98f 100644
--- a/lib/compiler/src/beam_core_to_ssa.erl
+++ b/lib/compiler/src/beam_core_to_ssa.erl
@@ -1877,10 +1877,14 @@ group_keeping_order_fun(C1) ->
{{S,U,T1,_,Next}, {S,U,_T2,_,Next}}
when T1 =:= integer; T1 =:= binary ->
%% The patterns in clauses `C1` and `C`
- %% match the same number of bits, meaning
- %% that clause `C` clause will not be
- %% reached if clause `C1` succeeds.
- true;
+ %% match the same number of bits. If the
+ %% value for clause `C1` is a variable,
+ %% clause `C1` will always be reached and
+ %% clause `C` will never be reached.
+ case arg_arg(clause_arg(C1)) of
+ #cg_bin_seg{seg=#b_var{}} -> true;
+ _ -> false
+ end;
{_, _} ->
false
end
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index fba52fb1b4..e2b8398f02 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -58,7 +58,8 @@
gh_6410/1,bs_match/1,
binary_aliases/1,gh_6923/1,
bs_test_tail/1,
- otp_19019/1]).
+ otp_19019/1,
+ gh_10878/1]).
-export([coverage_id/1,coverage_external_ignore/2]).
@@ -102,7 +103,8 @@ groups() ->
gh_6410,bs_match,binary_aliases,
gh_6923,
bs_test_tail,
- otp_19019]}].
+ otp_19019,
+ gh_10878]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -3360,6 +3362,35 @@ do_otp_19019(A) ->
ok
end.
+gh_10878(_Config) ->
+ {~"M", ~"Z"} = gh_10878_decode(id(~"MZ")),
+ ~"X" = gh_10878_decode(id(~"X=")),
+
+ 0 = count_newlines(~""),
+ 1 = count_newlines(~"\n"),
+ 1 = count_newlines(~"abc\n"),
+ 2 = count_newlines(~"abc\n\n"),
+ 2 = count_newlines(~"abc\nxyz\n"),
+
+ ok.
+
+gh_10878_decode(Encoded) ->
+ case Encoded of
+ <<A:1/binary, "=">> -> A;
+ <<A:1/binary, B:1/binary>> -> {A,B}
+ end.
+
+count_newlines(Bin) ->
+ count_newlines(id(Bin), 0).
+
+count_newlines(<<$\n,B/binary>>, Count) ->
+ count_newlines(B, Count + 1);
+count_newlines(<<_:1/unit:8,B/binary>>, Count) ->
+ %% The pattern in this clause is supposed to be combined with the
+ %% pattern in the previous clause.
+ count_newlines(B, Count);
+count_newlines(<<>>, Count) ->
+ Count.
%%% Utilities.
--
2.51.0