File 0340-Fix-optimization-of-binary-construction.patch of Package erlang
From 9d8a4a145ad27f9a2551d141a4c9b39e22730b31 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org>
Date: Thu, 20 Feb 2020 12:17:17 +0100
Subject: [PATCH 4/4] Fix optimization of binary construction
beam_ssa_opt would crash when attempting to optimize this
expression:
    << <<$t/little-signed>>:42/native-bytes >>.
sys_core_fold would usually try to optimize this kind of the
expression, but in this case it was fooled by the redundant
`native` flag.
---
 lib/compiler/src/beam_ssa_opt.erl        |  9 +++++++--
 lib/compiler/src/sys_core_fold.erl       | 20 +++++++++++---------
 lib/compiler/test/bs_construct_SUITE.erl |  6 ++++++
 3 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl
index f2c8434f8b..625e91f619 100644
--- a/lib/compiler/src/beam_ssa_opt.erl
+++ b/lib/compiler/src/beam_ssa_opt.erl
@@ -1784,8 +1784,13 @@ opt_bs_put(#b_set{args=[#b_literal{val=Type},#b_literal{val=Flags},
                     I = I0#b_set{args=Args},
                     opt_bs_put(I);
                 {binary,_} when is_bitstring(Val) ->
-                    <<Bitstring:EffectiveSize/bits,_/bits>> = Val,
-                    [Bitstring];
+                    case Val of
+                        <<Bitstring:EffectiveSize/bits,_/bits>> ->
+                            [Bitstring];
+                        _ ->
+                            %% Specified size exceeds size of bitstring.
+                            not_possible
+                    end;
                 {float,Endian} ->
                     try
                         [opt_bs_put_float(Val, EffectiveSize, Endian)]
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 77d762a102..6666245c14 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -683,15 +683,7 @@ eval_binary(#c_binary{anno=Anno,segments=Ss}=Bin) ->
 eval_binary_1([#c_bitstr{val=#c_literal{val=Val},size=#c_literal{val=Sz},
 			 unit=#c_literal{val=Unit},type=#c_literal{val=Type},
 			 flags=#c_literal{val=Flags}}|Ss], Acc0) ->
-    Endian = case member(big, Flags) of
-		 true ->
-		     big;
-		 false ->
-		     case member(little, Flags) of
-			 true -> little;
-			 false -> throw(impossible) %Native endian.
-		     end
-	     end,
+    Endian = bs_endian(Flags),
 
     %% Make sure that the size is reasonable.
     case Type of
@@ -741,6 +733,11 @@ eval_binary_1([#c_bitstr{val=#c_literal{val=Val},size=#c_literal{val=Sz},
 	    throw(impossible)
     end,
 
+    case Endian =:= native andalso Type =/= binary of
+        true -> throw(impossible);
+        false -> ok
+    end,
+
     %% Evaluate the field.
     try eval_binary_2(Acc0, Val, Sz, Unit, Type, Endian) of
 	Acc -> eval_binary_1(Ss, Acc)
@@ -804,6 +801,11 @@ eval_binary_2(Acc, Val, all, Unit, binary, _) ->
 eval_binary_2(Acc, Val, Size, Unit, binary, _) ->
     <<Acc/bitstring,Val:(Size*Unit)/bitstring>>.
 
+bs_endian([big=E|_]) -> E;
+bs_endian([little=E|_]) -> E;
+bs_endian([native=E|_]) -> E;
+bs_endian([_|Fs]) -> bs_endian(Fs).
+
 %% Count the number of bits approximately needed to store Int.
 %% (We don't need an exact result for this purpose.)
 
diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl
index aa4f302036..1c61d6cce4 100644
--- a/lib/compiler/test/bs_construct_SUITE.erl
+++ b/lib/compiler/test/bs_construct_SUITE.erl
@@ -344,6 +344,12 @@ fail(Config) when is_list(Config) ->
     {'EXIT',{badarg,_}} = (catch <<13:(put(?FUNCTION_NAME, 17))>>),
     17 = erase(?FUNCTION_NAME),
 
+    %% Size exceeds length of binary. 'native' is redundant for
+    %% binaries, but when it was present sys_core_fold would not
+    %% detect the overlong binary and beam_ssa_opt would crash.
+    {'EXIT',{badarg,_}} = (catch << <<$t/little-signed>>:42/native-bytes >>),
+    {'EXIT',{badarg,_}} = (catch << <<$t/little-signed>>:42/bytes >>),
+
     ok.
 
 float_bin(Config) when is_list(Config) ->
-- 
2.16.4