diff options
| author | John Högberg <john@erlang.org> | 2023-04-24 18:16:45 +0200 |
|---|---|---|
| committer | John Högberg <john@erlang.org> | 2023-04-24 19:33:06 +0200 |
| commit | 1c97ccc05722e0075ecdf22951d8653b96d06b47 (patch) | |
| tree | 6d218c39c53cae11e2783cc1298e0b13059bb7d2 | |
| parent | 17d5be464eb8f9f95c26ac9c92b040cdf8447fa0 (diff) | |
| download | erlang-1c97ccc05722e0075ecdf22951d8653b96d06b47.tar.gz | |
dialyzer: Fix crash on weird segment sizes
Fixes #7138
| -rw-r--r-- | lib/dialyzer/src/dialyzer_dataflow.erl | 23 | ||||
| -rw-r--r-- | lib/dialyzer/test/small_SUITE_data/results/bs_segments | 3 | ||||
| -rw-r--r-- | lib/dialyzer/test/small_SUITE_data/src/bs_segments.erl | 7 |
3 files changed, 20 insertions, 13 deletions
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. |
