Skip to content

Commit

Permalink
Eliminate Dialyzer crash for ill-typed code
Browse files Browse the repository at this point in the history
Closes #6419
  • Loading branch information
bjorng committed Nov 4, 2022
1 parent 19bce3c commit 14af146
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 15 deletions.
18 changes: 15 additions & 3 deletions lib/dialyzer/src/dialyzer_dataflow.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1599,7 +1599,8 @@ bind_bin_segs([Seg|Segs], BinType, Acc, Map, State) ->
Val = cerl:bitstr_val(Seg),
SegType = cerl:concrete(cerl:bitstr_type(Seg)),
UnitVal = cerl:concrete(cerl:bitstr_unit(Seg)),
case cerl:bitstr_bitsize(Seg) of
Size = cerl:bitstr_size(Seg),
case bitstr_bitsize_type(Size) of
all ->
binary = SegType, [] = Segs, %% just an assert
T = t_inf(t_bitstr(UnitVal, 0), BinType),
Expand All @@ -1613,8 +1614,7 @@ bind_bin_segs([Seg|Segs], BinType, Acc, Map, State) ->
Map, State, false, []),
Type = t_binary(),
bind_bin_segs(Segs, BinType, [Type|Acc], Map1, State);
BitSz when is_integer(BitSz); BitSz =:= any ->
Size = cerl:bitstr_size(Seg),
any ->
{Map1, [SizeType]} = do_bind_pat_vars([Size], [t_non_neg_integer()],
Map, State, false, []),
Opaques = State#state.opaques,
Expand Down Expand Up @@ -1665,6 +1665,18 @@ bind_bin_segs([Seg|Segs], BinType, Acc, Map, State) ->
bind_bin_segs([], _BinType, Acc, Map, _State) ->
{Map, lists:reverse(Acc)}.

bitstr_bitsize_type(Size) ->
case cerl:is_literal(Size) of
true ->
case cerl:concrete(Size) of
all -> all;
undefined -> utf;
_ -> any
end;
false ->
any
end.

%% Return the infimum (meet) of ExpectedType and Type if is not
%% t_none(), and raise a bind_error() it is t_none().
bind_checked_inf(Pat, ExpectedType, Type, Opaques) ->
Expand Down
29 changes: 18 additions & 11 deletions lib/dialyzer/src/dialyzer_typesig.erl
Original file line number Diff line number Diff line change
Expand Up @@ -255,17 +255,24 @@ traverse(Tree, DefinedVars, State) ->
{State1, [SizeType, ValType]} =
traverse_list([Size, Val], DefinedVars, State),
{State2, TypeConstr, BinValTypeConstr} =
case cerl:bitstr_bitsize(Tree) of
all ->
T = t_bitstr(UnitVal, 0),
{State1, T, T};
utf ->
%% contains an integer number of bytes
T = t_binary(),
{State1, T, T};
N when is_integer(N) ->
{State1, t_bitstr(0, N), t_bitstr(1, N)};
any -> % Size is not a literal
case cerl:is_literal(Size) of
true ->
case cerl:concrete(Size) of
all ->
T = t_bitstr(UnitVal, 0),
{State1, T, T};
undefined -> %utf-8/16/32
%% contains an integer number of bytes
T = t_binary(),
{State1, T, T};
N0 when is_integer(N0) ->
N = N0 * UnitVal,
{State1, t_bitstr(0, N), t_bitstr(1, N)};
_ ->
{State1, t_none(), t_none()}
end;
false ->
%% Size is not a literal
T1 = ?mk_fun_var(bitstr_constr(SizeType, UnitVal), [SizeType]),
T2 =
?mk_fun_var(bitstr_constr(SizeType, UnitVal, match), [SizeType]),
Expand Down
4 changes: 4 additions & 0 deletions lib/dialyzer/test/small_SUITE_data/results/bs_fail_constr
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ bs_fail_constr.erl:11:1: Function w3/1 has no local return
bs_fail_constr.erl:12:8: Binary construction will fail since the size field S in segment 42:S has type neg_integer()
bs_fail_constr.erl:14:1: Function w4/1 has no local return
bs_fail_constr.erl:15:5: Binary construction will fail since the value field V in segment V/utf32 has type float()
bs_fail_constr.erl:18:1: Function bad_size_1/1 has no local return
bs_fail_constr.erl:18:1: The pattern <<X:[]>> can never match the type any()
bs_fail_constr.erl:21:1: Function bad_size_2/1 has no local return
bs_fail_constr.erl:24:9: The pattern <<X:Size>> can never match the type any()
bs_fail_constr.erl:5:1: Function w1/1 has no local return
bs_fail_constr.erl:6:5: Binary construction will fail since the value field V in segment V has type float()
bs_fail_constr.erl:8:1: Function w2/1 has no local return
Expand Down
13 changes: 12 additions & 1 deletion lib/dialyzer/test/small_SUITE_data/src/bs_fail_constr.erl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-module(bs_fail_constr).

-export([w1/1, w2/1, w3/1, w4/1]).
-export([w1/1, w2/1, w3/1, w4/1, bad_size_1/1, bad_size_2/1]).

w1(V) when is_float(V) ->
<<V/integer>>.
Expand All @@ -13,3 +13,14 @@ w3(S) when is_integer(S), S < 0 ->

w4(V) when is_float(V) ->
<<V/utf32>>.

%% GH-6419
bad_size_1(<<X:[]>>) ->
ok.

bad_size_2(Bin) ->
Size = [],
case Bin of
<<X:Size>> ->
ok
end.

0 comments on commit 14af146

Please sign in to comment.