Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eliminate Dialyzer crash for ill-typed code #6429

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.