1
1
%% -*- erlang-indent-level: 2 -*-
2
2
%%-----------------------------------------------------------------------
5
%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
5
%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
7
7
%% The contents of this file are subject to the Erlang Public License,
8
8
%% Version 1.1, (the "License"); you may not use this file except in
9
9
%% compliance with the License. You should have received a copy of the
10
10
%% Erlang Public License along with this software. If not, it can be
11
11
%% retrieved online at http://www.erlang.org/.
13
13
%% Software distributed under the License is distributed on an "AS IS"
14
14
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
15
15
%% the License for the specific language governing rights and limitations
16
16
%% under the License.
21
21
%%%----------------------------------------------------------------------
22
22
%%% File : dialyzer_races.erl
23
23
%%% Author : Maria Christakis <christakismaria@gmail.com>
24
%%% Description : Utility functions for race condition detection
24
%%% Description : Utility functions for race condition detection
26
26
%%% Created : 21 Nov 2008 by Maria Christakis <christakismaria@gmail.com>
27
27
%%%----------------------------------------------------------------------
39
39
let_tag_new/2, new/0, put_curr_fun/3, put_fun_args/2,
40
40
put_race_analysis/2, put_race_list/3]).
42
-export_type([races/0, mfa_or_funlbl/0, core_vars/0]).
42
44
-include("dialyzer.hrl").
44
46
%%% ===========================================================================
51
53
-define(no_arg, no_arg).
52
54
-define(no_label, no_label).
55
-define(bypassed, bypassed).
54
57
-define(WARN_WHEREIS_REGISTER, warn_whereis_register).
58
-define(WARN_WHEREIS_UNREGISTER, warn_whereis_unregister).
55
59
-define(WARN_ETS_LOOKUP_INSERT, warn_ets_lookup_insert).
56
60
-define(WARN_MNESIA_DIRTY_READ_WRITE, warn_mnesia_dirty_read_write).
57
61
-define(WARN_NO_WARN, warn_no_warn).
65
69
-type mfa_or_funlbl() :: label() | mfa().
67
-type label_type() :: label() | [label()] | {label()} | ?no_label.
68
-type args() :: [label_type() | [string()]].
69
-type core_vars() :: cerl:cerl() | ?no_arg.
70
-type var_to_map() :: core_vars() | [cerl:cerl()].
71
-type core_args() :: [core_vars()] | 'empty'.
72
-type op() :: 'bind' | 'unbind'.
71
-type label_type() :: label() | [label()] | {label()} | ?no_label.
72
-type args() :: [label_type() | [string()]].
73
-type core_vars() :: cerl:cerl() | ?no_arg | ?bypassed.
74
-type var_to_map1() :: core_vars() | [cerl:cerl()].
75
-type var_to_map2() :: cerl:cerl() | [cerl:cerl()] | ?bypassed.
76
-type core_args() :: [core_vars()] | 'empty'.
77
-type op() :: 'bind' | 'unbind'.
74
79
-type dep_calls() :: 'whereis' | 'ets_lookup' | 'mnesia_dirty_read'.
75
-type warn_calls() :: 'register' | 'ets_insert' | 'mnesia_dirty_write'.
76
-type call() :: 'whereis' | 'register' | 'ets_new' | 'ets_lookup'
77
| 'ets_insert' | 'mnesia_dirty_read1'
80
-type warn_calls() :: 'register' | 'unregister' | 'ets_insert'
81
| 'mnesia_dirty_write'.
82
-type call() :: 'whereis' | 'register' | 'unregister' | 'ets_new'
83
| 'ets_lookup' | 'ets_insert' | 'mnesia_dirty_read1'
78
84
| 'mnesia_dirty_read2' | 'mnesia_dirty_write1'
79
| 'mnesia_dirty_write2' | 'function_call'.
80
-type race_tag() :: 'whereis_register' | 'ets_lookup_insert'
81
| 'mnesia_dirty_read_write'.
85
| 'mnesia_dirty_write2' | 'function_call'.
86
-type race_tag() :: 'whereis_register' | 'whereis_unregister'
87
| 'ets_lookup_insert' | 'mnesia_dirty_read_write'.
83
-record(beg_clause, {arg :: var_to_map(),
89
-record(beg_clause, {arg :: var_to_map1(),
90
pats :: var_to_map1(),
85
91
guard :: cerl:cerl()}).
86
-record(end_clause, {arg :: var_to_map(),
92
-record(end_clause, {arg :: var_to_map1(),
93
pats :: var_to_map1(),
88
94
guard :: cerl:cerl()}).
89
95
-record(end_case, {clauses :: [#end_clause{}]}).
90
96
-record(curr_fun, {status :: 'in' | 'out',
99
105
arg_types :: [erl_types:erl_type()],
100
106
vars :: [core_vars()],
107
state :: _, %% XXX: recursive
102
108
file_line :: file_line(),
103
109
var_map :: dict()}).
104
110
-record(fun_call, {caller :: mfa_or_funlbl(),
105
111
callee :: mfa_or_funlbl(),
106
112
arg_types :: [erl_types:erl_type()],
107
113
vars :: [core_vars()]}).
108
-record(let_tag, {var :: var_to_map(),
109
arg :: var_to_map()}).
114
-record(let_tag, {var :: var_to_map1(),
115
arg :: var_to_map1()}).
110
116
-record(warn_call, {call_name :: warn_calls(),
112
118
var_map :: dict()}).
114
120
-type case_tags() :: 'beg_case' | #beg_clause{} | #end_clause{} | #end_case{}.
115
-type code() :: [#dep_call{} | #warn_call{} | #fun_call{} |
121
-type code() :: [#dep_call{} | #fun_call{} | #warn_call{} |
116
122
#curr_fun{} | #let_tag{} | case_tags() | race_tag()].
118
124
-type table_var() :: label() | ?no_label.
153
159
%%% ===========================================================================
155
161
-spec store_race_call(mfa_or_funlbl(), [erl_types:erl_type()], [core_vars()],
156
file_line(), dialyzer_dataflow:state()) ->
162
file_line(), dialyzer_dataflow:state()) ->
157
163
dialyzer_dataflow:state().
159
165
store_race_call(Fun, ArgTypes, Args, FileLine, State) ->
162
168
CurrFunLabel = Races#races.curr_fun_label,
163
169
RaceTags = Races#races.race_tags,
164
170
CleanState = dialyzer_dataflow:state__records_only(State),
165
{NewRaceList, NewRaceListSize, NewRaceTags, NewTable} =
171
{NewRaceList, NewRaceListSize, NewRaceTags, NewTable} =
167
173
{_Module, module_info, A} when A =:= 0 orelse A =:= 1 ->
168
174
{[], 0, RaceTags, no_t};
180
186
fun_mfa = CurrFun, fun_label = CurrFunLabel},
181
187
{[#warn_call{call_name = register, args = VarArgs}|
182
188
RaceList], RaceListSize + 1, [RaceFun|RaceTags], no_t};
189
{erlang, unregister, 1} ->
190
VarArgs = format_args(Args, ArgTypes, CleanState, unregister),
191
RaceFun = #race_fun{mfa = Fun, args = VarArgs,
192
arg_types = ArgTypes, vars = Args,
193
file_line = FileLine, index = RaceListSize,
194
fun_mfa = CurrFun, fun_label = CurrFunLabel},
195
{[#warn_call{call_name = unregister, args = VarArgs}|
196
RaceList], RaceListSize + 1, [RaceFun|RaceTags], no_t};
183
197
{erlang, whereis, 1} ->
184
198
VarArgs = format_args(Args, ArgTypes, CleanState, whereis),
185
199
{[#dep_call{call_name = whereis, args = VarArgs,
282
296
{erlang, register, 2} -> ?WARN_WHEREIS_REGISTER;
297
{erlang, unregister, 1} -> ?WARN_WHEREIS_UNREGISTER;
283
298
{ets, insert, 2} -> ?WARN_ETS_LOOKUP_INSERT;
284
299
{mnesia, dirty_write, _A} -> ?WARN_MNESIA_DIRTY_READ_WRITE
287
302
state__renew_curr_fun(CurrFun,
288
303
state__renew_curr_fun_label(CurrFunLabel,
289
304
state__renew_race_list(lists:nthtail(length(RaceList) - Index,
291
306
DepList = fixup_race_list(RaceWarnTag, VarArgs, State1),
292
307
{State2, RaceWarn} =
293
308
get_race_warn(Fun, Args, ArgTypes, DepList, State),
320
336
lists:reverse(NewRaceList), [], CurrFun,
321
337
WarnVarArgs, RaceWarnTag, dict:new(),
322
338
[], [], [], 2 * ?local, NewState),
324
fixup_race_backward(CurrFun, Calls, Calls, [], ?local),
339
Parents = fixup_race_backward(CurrFun, Calls, Calls, [], ?local),
325
340
UParents = lists:usort(Parents),
327
filter_parents(UParents, UParents, Digraph),
341
Filtered = filter_parents(UParents, UParents, Digraph),
329
343
case lists:member(CurrFun, Filtered) of
330
344
true -> Filtered;
402
416
{ok, Fun} = Name,
403
417
{ok, Int} = Label,
405
dialyzer_callgraph:get_race_code(Callgraph)) of
418
case dict:find(Fun, dialyzer_callgraph:get_race_code(Callgraph)) of
407
420
{NewCurrFun, NewCurrFunLabel, NewCalls, Tail, NewRaceList,
408
421
NewRaceVarMap, NewFunDefVars, NewFunCallVars, NewFunArgTypes,
411
424
Races = dialyzer_dataflow:state__get_races(State),
412
425
{RetCurrFun, RetCurrFunLabel, RetCalls, RetCode,
413
426
RetRaceList, RetRaceVarMap, RetFunDefVars, RetFunCallVars,
414
RetFunArgTypes, RetNestingLevel} =
427
RetFunArgTypes, RetNestingLevel} =
415
428
fixup_race_forward_helper(NewCurrFun,
416
429
NewCurrFunLabel, Fun, Int, NewCalls, NewCalls,
417
430
[#curr_fun{status = out, mfa = NewCurrFun,
460
473
#dep_call{call_name = whereis} ->
461
474
case RaceWarnTag of
462
?WARN_WHEREIS_REGISTER ->
475
WarnWhereis when WarnWhereis =:= ?WARN_WHEREIS_REGISTER orelse
476
WarnWhereis =:= ?WARN_WHEREIS_UNREGISTER ->
463
477
{[Head#dep_call{var_map = RaceVarMap}|RaceList],
464
478
[], NestingLevel, false};
466
480
{RaceList, [], NestingLevel, false}
468
#dep_call{call_name = ets_lookup, args = DepCallArgs} ->
482
#dep_call{call_name = ets_lookup} ->
469
483
case RaceWarnTag of
470
484
?WARN_ETS_LOOKUP_INSERT ->
471
[Tab, Names, _, _] = DepCallArgs,
472
case compare_var_list(Tab,
473
dialyzer_callgraph:get_public_tables(Callgraph),
477
dialyzer_callgraph:get_named_tables(Callgraph)) <
480
{[Head#dep_call{var_map = RaceVarMap}|RaceList],
481
[], NestingLevel, false};
483
{RaceList, [], NestingLevel, false}
485
{[Head#dep_call{var_map = RaceVarMap}|RaceList],
486
[], NestingLevel, false};
486
488
{RaceList, [], NestingLevel, false}
494
496
{RaceList, [], NestingLevel, false}
496
#warn_call{call_name = register} ->
498
#warn_call{call_name = RegCall} when RegCall =:= register orelse
499
RegCall =:= unregister ->
497
500
case RaceWarnTag of
498
?WARN_WHEREIS_REGISTER ->
501
WarnWhereis when WarnWhereis =:= ?WARN_WHEREIS_REGISTER orelse
502
WarnWhereis =:= ?WARN_WHEREIS_UNREGISTER ->
499
503
{[Head#warn_call{var_map = RaceVarMap}|RaceList],
500
504
[], NestingLevel, false};
502
506
{RaceList, [], NestingLevel, false}
504
#warn_call{call_name = ets_insert, args = WarnCallArgs} ->
508
#warn_call{call_name = ets_insert} ->
505
509
case RaceWarnTag of
506
510
?WARN_ETS_LOOKUP_INSERT ->
507
[Tab, Names, _, _] = WarnCallArgs,
508
case compare_var_list(Tab,
509
dialyzer_callgraph:get_public_tables(Callgraph),
513
dialyzer_callgraph:get_named_tables(Callgraph)) <
516
{[Head#warn_call{var_map = RaceVarMap}|RaceList],
517
[], NestingLevel, false};
519
{RaceList, [], NestingLevel, false}
511
{[Head#warn_call{var_map = RaceVarMap}|RaceList],
512
[], NestingLevel, false};
522
514
{RaceList, [], NestingLevel, false}
563
555
PublicTables = dialyzer_callgraph:get_public_tables(Callgraph),
564
556
NamedTables = dialyzer_callgraph:get_named_tables(Callgraph),
566
558
var_type_analysis(FunDefVars, FunArgTypes, WarnVarArgs,
567
559
RaceWarnTag, RaceVarMap,
568
560
dialyzer_dataflow:state__records_only(State)),
575
567
{[#warn_call{call_name = register, args = WarnVarArgs,
576
568
var_map = RaceVarMap}],
570
whereis_unregister ->
571
{[#warn_call{call_name = unregister, args = WarnVarArgs,
572
var_map = RaceVarMap}],
578
574
ets_lookup_insert ->
580
576
[#warn_call{call_name = ets_insert, args = WarnVarArgs,
581
577
var_map = RaceVarMap}],
582
578
[Tab, Names, _, _] = WarnVarArgs,
584
580
compare_var_list(Tab, PublicTables, RaceVarMap)
586
582
length(Names -- NamedTables) < length(Names) of
618
614
#curr_fun{mfa = CurrFun2, label = CurrFunLabel2,
619
615
var_map = RaceVarMap2, def_vars = FunDefVars2,
620
616
call_vars = FunCallVars2, arg_types = FunArgTypes2},
621
Code2, NestingLevel2} =
617
Code2, NestingLevel2} =
622
618
remove_clause(NewRL,
623
619
#curr_fun{mfa = CurrFun, label = CurrFunLabel,
624
620
var_map = RaceVarMap1,
630
626
RaceVarMap2, FunDefVars2, FunCallVars2, FunArgTypes2,
631
627
NestingLevel2, false};
633
{CurrFun, CurrFunLabel, Tail, NewRL, RaceVarMap1,
629
{CurrFun, CurrFunLabel, Tail, NewRL, RaceVarMap1,
634
630
FunDefVars, FunCallVars, FunArgTypes, NewNL, false}
636
632
#end_clause{arg = Arg, pats = Pats, guard = Guard} ->
761
757
{[Vars, WVA2, WVA3, WVA4], false}
759
?WARN_WHEREIS_UNREGISTER ->
760
[WVA1, WVA2] = WarnVarArgs1,
763
[find_all_bound_vars(V, RaceVarMap1) || V <- WVA1]),
764
case {Vars, CurrLevel} of
768
{WarnVarArgs, false};
770
{[Vars, WVA2], false}
763
772
?WARN_ETS_LOOKUP_INSERT ->
764
773
[WVA1, WVA2, WVA3, WVA4] = WarnVarArgs1,
805
814
get_deplist_paths(Tail, WarnVarArgs2, RaceWarnTag, RaceVarMap1,
806
815
CurrLevel1, PublicTables, NamedTables)
808
#warn_call{call_name = register, args = WarnVarArgs1,
809
var_map = RaceVarMap1} ->
817
#warn_call{call_name = RegCall, args = WarnVarArgs1,
818
var_map = RaceVarMap1} when RegCall =:= register orelse
819
RegCall =:= unregister ->
810
820
case compare_first_arg(WarnVarArgs, WarnVarArgs1, RaceVarMap1) of
811
821
true -> {[], false, false};
812
822
NewWarnVarArgs ->
861
871
PublicTables, NamedTables) ->
862
872
{DepList, IsPublic, Continue} =
863
873
get_deplist_paths(fixup_case_path(RaceList, 0), WarnVarArgs,
864
RaceWarnTag, RaceVarMap, CurrLevel,
874
RaceWarnTag, RaceVarMap, CurrLevel,
865
875
PublicTables, NamedTables),
866
876
{fixup_case_rest_paths(RaceList, 0), DepList, IsPublic, Continue}.
931
941
#curr_fun{mfa = NewCurrFun, label = NewCurrFunLabel,
932
942
var_map = NewRaceVarMap, def_vars = NewFunDefVars,
933
943
call_vars = NewFunCallVars, arg_types = NewFunArgTypes},
934
NewCode, NewNestingLevel} =
944
NewCode, NewNestingLevel} =
935
945
remove_clause(RaceList,
936
946
#curr_fun{mfa = CurrFun, label = CurrFunLabel, var_map = RaceVarMap,
937
947
def_vars = FunDefVars, call_vars = FunCallVars,
963
973
arg_types = NewFunTypes}],
964
974
[#curr_fun{status = in, mfa = Fun,
965
975
label = FunLabel, var_map = NewRaceVarMap,
966
def_vars = Args, call_vars = NewFunArgs,
976
def_vars = Args, call_vars = NewFunArgs,
967
977
arg_types = NewFunTypes}|
968
978
lists:reverse(StateRaceList)] ++
969
979
RetC, NewRaceVarMap),
1407
1417
lists_key_members_lists_helper(_Elem, _List, _N) ->
1410
1420
lists_key_replace(N, List, NewMember) ->
1411
1421
{Before, [_|After]} = lists:split(N - 1, List),
1412
1422
Before ++ [NewMember|After].
1417
1427
refine_race(RaceCall, WarnVarArgs, RaceWarnTag, DependencyList, RaceVarMap) ->
1418
1428
case RaceWarnTag of
1419
?WARN_WHEREIS_REGISTER ->
1429
WarnWhereis when WarnWhereis =:= ?WARN_WHEREIS_REGISTER orelse
1430
WarnWhereis =:= ?WARN_WHEREIS_UNREGISTER ->
1420
1431
case RaceCall of
1421
1432
#dep_call{call_name = ets_lookup} ->
1422
1433
DependencyList;
1455
1466
false -> DependencyList
1458
remove_clause(RaceList, CurrTuple, Code, NestingLevel) ->
1469
remove_clause(RaceList, CurrTuple, Code, NestingLevel) ->
1459
1470
NewRaceList = fixup_case_rest_paths(RaceList, 0),
1460
1471
{NewCurrTuple, NewCode} =
1461
1472
cleanup_clause_code(CurrTuple, Code, 0, NestingLevel),
1658
1669
compare_var_list(VA1, WVA1, RaceVarMap) orelse
1659
1670
compare_argtypes(VA2, WVA2)
1673
?WARN_WHEREIS_UNREGISTER ->
1674
[VA1, VA2] = VarArgs,
1675
[WVA1, WVA2] = WarnVarArgs,
1676
case any_args(VA2) of
1677
true -> compare_var_list(VA1, WVA1, RaceVarMap);
1679
case any_args(WVA2) of
1680
true -> compare_var_list(VA1, WVA1, RaceVarMap);
1682
compare_var_list(VA1, WVA1, RaceVarMap) orelse
1683
compare_argtypes(VA2, WVA2)
1663
1686
?WARN_ETS_LOOKUP_INSERT ->
1670
1693
case any_args(WVA2) of
1671
1694
true -> compare_var_list(VA1, WVA1, RaceVarMap);
1673
1696
compare_var_list(VA1, WVA1, RaceVarMap) orelse
1674
1697
compare_argtypes(VA2, WVA2)
1678
1701
(case any_args(VA4) of
1680
1703
compare_var_list(VA3, WVA3, RaceVarMap);
1684
1707
compare_var_list(VA3, WVA3, RaceVarMap);
1686
compare_var_list(VA3, WVA3, RaceVarMap)
1687
orelse compare_argtypes(VA4, WVA4)
1709
compare_var_list(VA3, WVA3, RaceVarMap) orelse
1710
compare_argtypes(VA4, WVA4)
1690
1713
?WARN_MNESIA_DIRTY_READ_WRITE ->
1845
1869
[format_arg(Arg), format_type(Type, CleanState)];
1846
1870
format_args_1([Arg|Args], [Type|Types], CleanState) ->
1848
case cerl:is_literal(Arg) of
1849
true -> [?no_label, format_cerl(Arg)];
1850
false -> [format_arg(Arg), format_type(Type, CleanState)]
1872
case Arg =:= ?bypassed of
1873
true -> [?no_label, format_type(Type, CleanState)];
1875
case cerl:is_literal(Arg) of
1876
true -> [?no_label, format_cerl(Arg)];
1877
false -> [format_arg(Arg), format_type(Type, CleanState)]
1852
1880
List ++ format_args_1(Args, Types, CleanState).
1860
1888
lists_key_replace(2, StrArgList,
1861
1889
string:tokens(lists:nth(2, StrArgList), " |"));
1891
lists_key_replace(2, StrArgList,
1892
string:tokens(lists:nth(2, StrArgList), " |"));
1863
1894
StrArgList1 = lists_key_replace(2, StrArgList,
1864
1895
string:tokens(lists:nth(2, StrArgList), " |")),
1919
1950
[TupleStr2|_T] = string:tokens(TupleStr1, " ,"),
1920
1951
lists:flatten(string:tokens(TupleStr2, " |")).
1922
-spec race_var_map(var_to_map(), cerl:cerl() | [cerl:cerl()], dict(), op()) -> dict().
1953
-spec race_var_map(var_to_map1(), var_to_map2(), dict(), op()) -> dict().
1924
1955
race_var_map(Vars1, Vars2, RaceVarMap, Op) ->
1925
case Vars1 =:= ?no_arg of
1956
case Vars1 =:= ?no_arg orelse Vars1 =:= ?bypassed
1957
orelse Vars2 =:= ?bypassed of
1926
1958
true -> RaceVarMap;
1928
1960
case is_list(Vars1) andalso is_list(Vars2) of
2076
2108
{RaceVarMap1, RemoveClause orelse RemoveClause1}.
2078
2110
race_var_map_guard_helper1(Arg, Pats, RaceVarMap, Op) ->
2079
case Arg =:= ?no_arg of
2111
case Arg =:= ?no_arg orelse Arg =:= ?bypassed of
2080
2112
true -> {RaceVarMap, false};
2082
2114
case cerl:type(Arg) of
2102
2134
_Else -> {RaceVarMap, false}
2104
2136
false -> {RaceVarMap, false}
2106
2138
_Other -> {RaceVarMap, false}
2108
2140
_Other -> {RaceVarMap, false}
2140
2172
unbind_dict_vars(Var1, Var2,
2141
2173
bind_dict_vars_list(Var1, Labels -- [Var2],
2142
dict:erase(Var1, RaceVarMap)));
2174
dict:erase(Var1, RaceVarMap)));
2144
2176
unbind_dict_vars_helper(Labels, Var1, Var2, RaceVarMap)
2171
2203
[WVA1, WVA2, WVA3, WVA4] = WarnVarArgs,
2172
2204
ArgNos = lists_key_members_lists(WVA1, FunDefArgs),
2173
2205
[[lists_get(N, FunCallArgs) || N <- ArgNos], WVA2, WVA3, WVA4];
2206
?WARN_WHEREIS_UNREGISTER ->
2207
[WVA1, WVA2] = WarnVarArgs,
2208
ArgNos = lists_key_members_lists(WVA1, FunDefArgs),
2209
[[lists_get(N, FunCallArgs) || N <- ArgNos], WVA2];
2174
2210
?WARN_ETS_LOOKUP_INSERT ->
2175
2211
[WVA1, WVA2, WVA3, WVA4] = WarnVarArgs,
2176
2212
ArgNos1 = lists_key_members_lists(WVA1, FunDefArgs),
2181
2217
[WVA1, WVA2|T] = WarnVarArgs,
2182
2218
ArgNos = lists_key_members_lists(WVA1, FunDefArgs),
2183
2219
[[lists_get(N, FunCallArgs) || N <- ArgNos], WVA2|T]
2186
2222
var_type_analysis(FunDefArgs, FunCallTypes, WarnVarArgs, RaceWarnTag,
2187
2223
RaceVarMap, CleanState) ->
2188
FunVarArgs = format_args(FunDefArgs, FunCallTypes, CleanState,
2224
FunVarArgs = format_args(FunDefArgs, FunCallTypes, CleanState, function_call),
2190
2225
case RaceWarnTag of
2191
2226
?WARN_WHEREIS_REGISTER ->
2192
2227
[WVA1, WVA2, WVA3, WVA4] = WarnVarArgs,
2197
2232
NewWVA2 = string:tokens(lists:nth(N + 1, FunVarArgs), " |"),
2198
2233
[Vars, NewWVA2, WVA3, WVA4]
2235
?WARN_WHEREIS_UNREGISTER ->
2236
[WVA1, WVA2] = WarnVarArgs,
2237
Vars = find_all_bound_vars(WVA1, RaceVarMap),
2238
case lists_key_member_lists(Vars, FunVarArgs) of
2240
N when is_integer(N) ->
2241
NewWVA2 = string:tokens(lists:nth(N + 1, FunVarArgs), " |"),
2200
2244
?WARN_ETS_LOOKUP_INSERT ->
2201
2245
[WVA1, WVA2, WVA3, WVA4] = WarnVarArgs,
2202
2246
Vars1 = find_all_bound_vars(WVA1, RaceVarMap),
2218
2262
ets_tuple_argtypes1(lists:nth(N2 + 1, FunVarArgs), [], [], 0),
2220
2264
FirstVarArg ++ [Vars2, NewWVA4]
2223
2267
?WARN_MNESIA_DIRTY_READ_WRITE ->
2224
2268
[WVA1, WVA2|T] = WarnVarArgs,
2263
2307
-spec get_race_warnings(races(), dialyzer_dataflow:state()) ->
2264
2308
{races(), dialyzer_dataflow:state()}.
2266
2310
get_race_warnings(#races{race_warnings = RaceWarnings}, State) ->
2267
2311
get_race_warnings_helper(RaceWarnings, State).
2278
2322
get_reason(lists:keysort(7, DepList),
2279
2323
"might fail due to a possible race condition "
2280
2324
"caused by its combination with ");
2325
?WARN_WHEREIS_UNREGISTER ->
2326
get_reason(lists:keysort(7, DepList),
2327
"might fail due to a possible race condition "
2328
"caused by its combination with ");
2281
2329
?WARN_ETS_LOOKUP_INSERT ->
2282
2330
get_reason(lists:keysort(7, DepList),
2283
2331
"might have an unintended effect due to " ++
2336
2384
%%% ===========================================================================
2338
-spec beg_clause_new(var_to_map(), var_to_map(), cerl:cerl()) ->
2386
-spec beg_clause_new(var_to_map1(), var_to_map1(), cerl:cerl()) ->
2341
2389
beg_clause_new(Arg, Pats, Guard) ->
2351
2399
end_case_new(Clauses) ->
2352
2400
#end_case{clauses = Clauses}.
2354
-spec end_clause_new(var_to_map(), var_to_map(), cerl:cerl()) ->
2402
-spec end_clause_new(var_to_map1(), var_to_map1(), cerl:cerl()) ->
2357
2405
end_clause_new(Arg, Pats, Guard) ->
2358
2406
#end_clause{arg = Arg, pats = Pats, guard = Guard}.
2360
2408
-spec get_curr_fun(races()) -> mfa_or_funlbl().
2362
2410
get_curr_fun(#races{curr_fun = CurrFun}) ->
2365
2413
-spec get_curr_fun_args(races()) -> core_args().
2367
2415
get_curr_fun_args(#races{curr_fun_args = CurrFunArgs}) ->
2375
2423
-spec get_race_analysis(races()) -> boolean().
2377
2425
get_race_analysis(#races{race_analysis = RaceAnalysis}) ->
2380
2428
-spec get_race_list(races()) -> code().
2382
2430
get_race_list(#races{race_list = RaceList}) ->
2385
2433
-spec get_race_list_size(races()) -> non_neg_integer().
2387
2435
get_race_list_size(#races{race_list_size = RaceListSize}) ->
2390
-spec let_tag_new(var_to_map(), var_to_map()) -> #let_tag{}.
2438
-spec let_tag_new(var_to_map1(), var_to_map1()) -> #let_tag{}.
2392
2440
let_tag_new(Var, Arg) ->
2393
2441
#let_tag{var = Var, arg = Arg}.
2411
2459
empty -> Races#races{curr_fun_args = Args};
2412
2460
_Other -> Races
2415
2463
-spec put_race_analysis(boolean(), races()) ->
2418
2466
put_race_analysis(Analysis, Races) ->
2419
2467
Races#races{race_analysis = Analysis}.
2424
2472
put_race_list(RaceList, RaceListSize, Races) ->
2425
Races#races{race_list = RaceList,
2426
race_list_size = RaceListSize}.
2473
Races#races{race_list = RaceList, race_list_size = RaceListSize}.