File 0119-dialyzer-Fix-crash-on-weird-segment-sizes.patch of Package erlang
From 1c97ccc05722e0075ecdf22951d8653b96d06b47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20H=C3=B6gberg?= <john@erlang.org>
Date: Mon, 24 Apr 2023 18:16:45 +0200
Subject: [PATCH] dialyzer: Fix crash on weird segment sizes
Fixes #7138
---
lib/dialyzer/src/dialyzer_dataflow.erl | 23 ++++++++-----------
.../test/small_SUITE_data/results/bs_segments | 3 +++
.../test/small_SUITE_data/src/bs_segments.erl | 7 ++++++
3 files changed, 20 insertions(+), 13 deletions(-)
create mode 100644 lib/dialyzer/test/small_SUITE_data/results/bs_segments
create mode 100644 lib/dialyzer/test/small_SUITE_data/src/bs_segments.erl
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index bb77ea972f..7e0a75f062 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -1602,20 +1602,23 @@ bind_bin_segs([Seg|Segs], BinType, Acc, Map, State) ->
UnitVal = cerl:concrete(cerl:bitstr_unit(Seg)),
Size = cerl:bitstr_size(Seg),
case bitstr_bitsize_type(Size) of
- all ->
- binary = SegType, [] = Segs, %% just an assert
+ {literal, all} ->
+ binary = SegType, [] = Segs, %Assertion.
T = t_inf(t_bitstr(UnitVal, 0), BinType),
{Map1, [Type]} = do_bind_pat_vars([Val], [T], Map,
State, false, []),
Type1 = remove_local_opaque_types(Type, State#state.opaques),
bind_bin_segs(Segs, t_bitstr(0, 0), [Type1|Acc], Map1, State);
- utf -> % XXX: can possibly be strengthened
- true = lists:member(SegType, [utf8, utf16, utf32]),
+ SizeType when SegType =:= utf8; SegType =:= utf16; SegType =:= utf32 ->
+ {literal, undefined} = SizeType, %Assertion.
{Map1, [_]} = do_bind_pat_vars([Val], [t_integer()],
Map, State, false, []),
Type = t_binary(),
bind_bin_segs(Segs, BinType, [Type|Acc], Map1, State);
- any ->
+ {literal, N} when not is_integer(N); N < 0 ->
+ %% Bogus literal size, fails in runtime.
+ bind_error([Seg], BinType, t_none(), bind);
+ _ ->
{Map1, [SizeType]} = do_bind_pat_vars([Size], [t_non_neg_integer()],
Map, State, false, []),
Opaques = State#state.opaques,
@@ -1668,14 +1671,8 @@ bind_bin_segs([], _BinType, Acc, Map, _State) ->
bitstr_bitsize_type(Size) ->
case cerl:is_literal(Size) of
- true ->
- case cerl:concrete(Size) of
- all -> all;
- undefined -> utf;
- _ -> any
- end;
- false ->
- any
+ true -> {literal, cerl:concrete(Size)};
+ false -> variable
end.
%% Return the infimum (meet) of ExpectedType and Type if it describes a
diff --git a/lib/dialyzer/test/small_SUITE_data/results/bs_segments b/lib/dialyzer/test/small_SUITE_data/results/bs_segments
new file mode 100644
index 0000000000..0c3c9a0717
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/bs_segments
@@ -0,0 +1,3 @@
+
+bs_segments.erl:6:1: Function t/1 has no local return
+bs_segments.erl:6:1: The pattern <<_>> can never match the type any()
diff --git a/lib/dialyzer/test/small_SUITE_data/src/bs_segments.erl b/lib/dialyzer/test/small_SUITE_data/src/bs_segments.erl
new file mode 100644
index 0000000000..b1b8a2e866
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/bs_segments.erl
@@ -0,0 +1,7 @@
+-module(bs_segments).
+
+-export([t/1]).
+
+%% GH-7138: bogus segment sizes crashed the analysis.
+t(<<_:undefined>>) ->
+ ok.
--
2.35.3