2671
2725
state__warning_mode(#state{warning_mode = WM}) ->
2674
state__set_warning_mode(#state{tree_map = TreeMap, fun_tab = FunTab} = State) ->
2728
state__set_warning_mode(#state{tree_map = TreeMap, fun_tab = FunTab,
2729
races = Races} = State) ->
2675
2730
?debug("Starting warning pass\n", []),
2676
2731
Funs = dict:fetch_keys(TreeMap),
2677
2732
State#state{work = init_work([top|Funs--[top]]),
2678
fun_tab = FunTab, warning_mode = true}.
2733
fun_tab = FunTab, warning_mode = true,
2734
races = races__race_analysis(true, Races)}.
2736
state__race_analysis(Analysis, #state{races = Races} = State) ->
2737
State#state{races = races__race_analysis(Analysis, Races)}.
2680
2739
state__renew_curr_fun(CurrFun, CurrFunLabel,
2681
#state{callgraph = Callgraph, races = Races} = State) ->
2682
State#state{callgraph =
2683
races__renew_local_fun_label(CurrFun, CurrFunLabel, Callgraph),
2684
races = races__renew_curr_fun(CurrFun, CurrFunLabel, Races)}.
2686
state__renew_fun_args(Args,
2687
#state{callgraph = Callgraph, races = Races} = State) ->
2688
State#state{callgraph =
2689
races__renew_fun_args_1(Args, Races#dialyzer_races.curr_fun, Callgraph),
2690
races = races__renew_fun_args_2(Args, Races)}.
2692
state__renew_inter_module_calls(InterModuleCalls,
2693
#state{callgraph = Callgraph} = State) ->
2694
State#state{callgraph =
2695
races__renew_inter_module_calls(InterModuleCalls, Callgraph)}.
2697
state__renew_local_calls(#state{callgraph = Callgraph, races = Races} = State,
2699
State#state{races = races__renew_local_calls(Races, Callgraph, Operation)}.
2701
state__renew_module_local_call_label(Fun, #state{callgraph = Callgraph,
2702
races = Races} = State) ->
2703
State#state{callgraph =
2704
races__renew_module_local_call_label(Fun, Races#dialyzer_races.curr_fun,
2707
state__renew_processing_local_call(CaseCode, #state{races = Races} = State) ->
2709
races__renew_processing_local_call(CaseCode, Races)}.
2740
#state{races = Races} = State) ->
2741
State#state{races = races__renew_curr_fun(CurrFun, CurrFunLabel, Races)}.
2743
state__renew_fun_args(Args, #state{races = Races} = State) ->
2744
case state__warning_mode(State) of
2747
State#state{races = races__renew_fun_args(Args, Races)}
2711
2750
state__renew_race_list(RaceList, #state{races = Races} = State) ->
2712
2751
State#state{races = races__renew_race_list(RaceList, Races)}.
2753
state__renew_race_var_map(RaceVarMap, #state{callgraph = Callgraph} = State) ->
2754
State#state{callgraph =
2755
callgraph__renew_race_var_map(RaceVarMap, Callgraph)}.
2757
state__race_var_map(Arg, Pats, Guard,
2758
#state{callgraph = Callgraph} = State, Op) ->
2759
State#state{callgraph =
2760
callgraph__race_var_map(Arg, Pats, Guard, Callgraph, Op)}.
2762
state__check_race_var_map(Arg, Pat, Bool, State) ->
2763
case cerl:type(Pat) of
2765
[Arg1, Arg2] = cerl:call_args(Arg),
2766
case cerl:concrete(Pat) of
2768
state__race_var_map(Arg1, Arg2, no_guard, State, bind);
2770
state__race_var_map(Arg1, Arg2, no_guard, State, unbind)
2714
2775
state__renew_warnings(Warnings, State) ->
2715
2776
State#state{warnings = Warnings}.
3092
3128
%%% ===========================================================================
3130
%%% Callgraph and Races
3096
3132
%%% ===========================================================================
3134
races__race_analysis(Analysis, Races) ->
3135
Races#dialyzer_races{race_analysis = Analysis}.
3098
3137
races__renew_curr_fun(CurrFun, CurrFunLabel, Races) ->
3099
Races#dialyzer_races{curr_fun = CurrFun, curr_fun_label = CurrFunLabel}.
3101
races__renew_fun_args_1(Args, CurrFun, Callgraph = #dialyzer_callgraph{
3102
module_local_calls = ModuleLocalCalls,
3103
inter_module_calls = InterModuleCalls}) ->
3104
Callgraph#dialyzer_callgraph{module_local_calls =
3105
races__renew_fun_args_1_helper1(Args, CurrFun, ModuleLocalCalls),
3106
inter_module_calls =
3107
races__renew_fun_args_1_helper2(Args, CurrFun, InterModuleCalls)}.
3109
races__renew_fun_args_1_helper1(Args, CurrFun, ModuleLocalCalls) ->
3110
case ModuleLocalCalls of
3115
{TupleA, IntA, CurrFun, IntB, empty, CodeA, CodeB, Bool} ->
3116
{TupleA, IntA, CurrFun, IntB, Args, CodeA, CodeB, Bool};
3119
[NewHead|races__renew_fun_args_1_helper1(Args, CurrFun, Tail)]
3122
races__renew_fun_args_1_helper2(Args, CurrFun, InterModuleCalls) ->
3123
case InterModuleCalls of
3128
{TupleA, CurrFun, empty, ListA, ListB, BoolA, BoolB} ->
3129
{TupleA, CurrFun, Args, ListA, ListB, BoolA, BoolB};
3132
[NewHead|races__renew_fun_args_1_helper2(Args, CurrFun, Tail)]
3135
races__renew_fun_args_2(Args,
3136
#dialyzer_races{local_calls = LocalCalls} = Races) ->
3137
Races#dialyzer_races{local_calls =
3138
races__renew_fun_args_2_helper(Args, LocalCalls)}.
3140
races__renew_fun_args_2_helper(Args, LocalCalls) ->
3145
{Int, empty, RaceList, processing} ->
3146
[{Int, Args, RaceList, processing}|Tail];
3148
[Head|races__renew_fun_args_2_helper(Args, Tail)]
3152
races__renew_inter_module_calls(InterModuleCalls, Callgraph) ->
3153
Callgraph#dialyzer_callgraph{inter_module_calls = InterModuleCalls}.
3155
races__renew_local_calls(Races =
3156
#dialyzer_races{local_calls = LocalCalls,
3158
curr_fun_label=CurrFunLabel},
3159
#dialyzer_callgraph{module_local_calls =
3162
Races#dialyzer_races{local_calls =
3163
races__renew_local_calls_helper2(CurrFunLabel,
3164
races__renew_local_calls_helper1(CurrFunLabel, LocalCalls, CurrFun,
3165
ModuleLocalCalls, Operation), none, Operation)}.
3167
races__renew_local_calls_helper1(CurrFunLabel, LocalCalls, CurrFun,
3168
ModuleLocalCalls, Operation) ->
3171
races__check_module_local_calls(CurrFunLabel, CurrFun, ModuleLocalCalls)
3178
{CurrFunLabel, Args, RaceList, processing} ->
3179
[{CurrFunLabel, Args, RaceList, true}|Tail];
3180
{_Fun, _Args, _RaceList, _Bool} ->
3182
races__renew_local_calls_helper1(CurrFunLabel, Tail, CurrFun,
3183
ModuleLocalCalls, Operation)]
3188
races__renew_local_calls_helper2(CurrFunLabel, LocalCalls, Tuple, Operation) ->
3190
start -> LocalCalls;
3200
{CurrFunLabel, _Args1, RaceList, true} ->
3203
races__renew_local_calls_helper2(CurrFunLabel, Tail, Head,
3205
{CurrFunLabel, _Args2, FunRaceList, true} ->
3206
case length(FunRaceList) > length(RaceList) of
3207
true -> [Tuple|Tail];
3208
false -> [Head|Tail]
3212
[Head|races__renew_local_calls_helper2(CurrFunLabel, Tail, Tuple,
3218
races__renew_local_fun_label(CurrFun, CurrFunLabel,
3220
#dialyzer_callgraph{module_local_calls =
3221
ModuleLocalCalls}) ->
3222
Callgraph#dialyzer_callgraph{module_local_calls =
3223
races__renew_local_fun_label_helper(CurrFun, CurrFunLabel,
3226
races__renew_local_fun_label_helper(CurrFun, CurrFunLabel, ModuleLocalCalls) ->
3227
case ModuleLocalCalls of
3232
{CurrFun, _IntA, CurrFun, _IntB, ArgsB, CodeA, CodeB, Bool} ->
3233
{CurrFun, CurrFunLabel, CurrFun, CurrFunLabel, ArgsB, CodeA, CodeB,
3235
{CurrFun, _IntA, TupleB, IntB, ArgsB, CodeA, CodeB, Bool} ->
3236
{CurrFun, CurrFunLabel, TupleB, IntB, ArgsB, CodeA, CodeB, Bool};
3237
{TupleA, IntA, CurrFun, _IntB, ArgsB, CodeA, CodeB, Bool} ->
3238
{TupleA, IntA, CurrFun, CurrFunLabel, ArgsB, CodeA, CodeB, Bool};
3239
{_TupleA, _IntA, _TupleB, _IntB, _ArgsB, _CodeA, _CodeB, _Bool} ->
3243
races__renew_local_fun_label_helper(CurrFun, CurrFunLabel, Tail)]
3246
races__renew_module_local_call_label(Fun, CurrFun,
3248
#dialyzer_callgraph{module_local_calls =
3249
ModuleLocalCalls}) ->
3250
Callgraph#dialyzer_callgraph{module_local_calls =
3251
races__renew_module_local_call_label_helper(Fun, CurrFun,
3254
races__renew_module_local_call_label_helper(Fun, CurrFun, ModuleLocalCalls) ->
3255
case ModuleLocalCalls of
3259
{CurrFun, IntA, TupleB, Fun, ArgsB, CodeA, CodeB, _Bool} ->
3260
[{CurrFun, IntA, TupleB, Fun, ArgsB, CodeA, CodeB, true}|Tail];
3263
races__renew_module_local_call_label_helper(Fun, CurrFun, Tail)]
3267
races__renew_module_local_calls(Callgraph =
3268
#dialyzer_callgraph{module_local_calls =
3270
#dialyzer_races{local_calls = LocalCalls}) ->
3271
Callgraph#dialyzer_callgraph{module_local_calls =
3272
races__renew_module_local_calls_helper1(ModuleLocalCalls, LocalCalls)}.
3274
races__renew_module_local_calls_helper1(ModuleLocalCalls, LocalCalls) ->
3276
[] -> ModuleLocalCalls;
3277
[{Int, _Args, RaceList, _Bool}|Tail] ->
3278
NewModuleLocalCalls =
3279
races__renew_module_local_calls_helper2(Int, ModuleLocalCalls,
3280
lists:reverse(RaceList)),
3281
races__renew_module_local_calls_helper1(NewModuleLocalCalls, Tail)
3284
races__renew_module_local_calls_helper2(Int, ModuleLocalCalls, Code) ->
3285
case ModuleLocalCalls of
3290
{TupleA, Int, TupleB, Int, ArgsB, empty, empty, true} ->
3291
[{TupleA, Int, TupleB, Int, ArgsB, Code, Code, true}];
3292
{TupleA, Int, TupleB, IntB, ArgsB, empty, CodeB, true} ->
3293
[{TupleA, Int, TupleB, IntB, ArgsB, Code, CodeB, true}];
3294
{TupleA, IntA, TupleB, Int, ArgsB, CodeA, empty, true} ->
3295
[{TupleA, IntA, TupleB, Int, ArgsB, CodeA, Code, true}];
3296
{_TupleA, Int, _TupleB, _IntB, _ArgsB, empty, _CodeB, false} ->
3298
{_TupleA, _IntA, _TupleB, Int, _ArgsB, _CodeA, empty, false} ->
3300
{_TupleA, Int, _TupleB, Int, _ArgsB, empty, empty, false} ->
3304
NewHead ++ races__renew_module_local_calls_helper2(Int, Tail, Code)
3307
races__renew_processing_local_call(CaseCode, Races =
3308
#dialyzer_races{local_calls = LocalCalls}) ->
3309
Races#dialyzer_races{local_calls =
3310
races__renew_processing_local_call_helper(CaseCode, LocalCalls)}.
3312
races__renew_processing_local_call_helper(CaseCode, LocalCalls) ->
3317
{Int, Args, RaceList, processing} ->
3318
[{Int, Args, [CaseCode|RaceList], processing}|Tail];
3320
[Head|races__renew_processing_local_call_helper(CaseCode, Tail)]
3138
Races#dialyzer_races{curr_fun = CurrFun,
3139
curr_fun_label = CurrFunLabel,
3140
curr_fun_args = empty}.
3142
races__renew_fun_args(Args,
3143
#dialyzer_races{curr_fun_args = CurrFunArgs} = Races) ->
3145
empty -> Races#dialyzer_races{curr_fun_args = Args};
3149
callgraph__renew_code(Fun, FunArgs, Code, WarningMode,
3150
#dialyzer_callgraph{race_code = RaceCode} = Callgraph) ->
3154
Callgraph#dialyzer_callgraph{race_code =
3155
dict:store(Fun, [FunArgs, Code], RaceCode)}
3324
3158
races__renew_race_list(RaceList, Races) ->
3325
3159
Races#dialyzer_races{race_list = RaceList}.
3327
races__renew_race_warnings(Warnings, Races) ->
3328
Races#dialyzer_races{race_warnings = Warnings}.
3161
accumulate_race_var_map(Ret, Acc) ->
3162
KeysToAdd = dict:fetch_keys(Ret),
3163
accumulate_race_var_map_helper1(KeysToAdd, Ret, Acc).
3165
accumulate_race_var_map_helper1(KeysToAdd, Ret, Acc) ->
3169
accumulate_race_var_map_helper1(Tail, Ret,
3170
accumulate_race_var_map_helper2(Head, dict:fetch(Head, Ret), Acc))
3173
accumulate_race_var_map_helper2(Key, Values, Acc) ->
3177
accumulate_race_var_map_helper2(Key, Tail,
3178
dialyzer_races:bind_dict_vars(Key, Head, Acc))
3181
callgraph__renew_race_var_map(RaceVarMap, Callgraph) ->
3182
Callgraph#dialyzer_callgraph{race_var_map = RaceVarMap}.
3184
callgraph__race_var_map(Arg, Pats, Guard,
3185
#dialyzer_callgraph{race_var_map = RaceVarMap} = Callgraph, Op) ->
3188
no_guard -> RaceVarMap;
3190
case cerl:type(Guard) of
3192
CallName = cerl:call_name(Guard),
3193
case cerl:is_literal(CallName) of
3195
case cerl:concrete(CallName) of
3197
[Arg1, Arg2] = cerl:call_args(Guard),
3198
dialyzer_races:race_var_map(Arg1, Arg2, RaceVarMap,
3201
[Arg1, Arg2] = cerl:call_args(Guard),
3202
dialyzer_races:race_var_map(Arg1, Arg2, RaceVarMap,
3205
[Arg1, Arg2] = cerl:call_args(Guard),
3206
dialyzer_races:race_var_map(Arg1, Arg2, RaceVarMap,
3208
_Other -> RaceVarMap
3212
_Other -> RaceVarMap
3215
Callgraph#dialyzer_callgraph{race_var_map =
3216
dialyzer_races:race_var_map(Arg, Pats, NewRaceVarMap, Op)}.
3218
callgraph__renew_public_tables([Var], #dialyzer_races{new_table = Table},
3219
#dialyzer_callgraph{public_tables = PTables,
3220
named_tables = NTables} = Callgraph) ->
3224
VarLabel = get_label(Var),
3225
Callgraph#dialyzer_callgraph{public_tables = [VarLabel|PTables]};
3226
{named, NameLabel, Names} ->
3227
VarLabel = get_label(Var),
3230
?no_label -> [VarLabel];
3231
_Other -> [VarLabel, NameLabel]
3233
NamesToAdd = filter_named_tables(Names),
3234
Callgraph#dialyzer_callgraph{
3235
public_tables = lists:usort(PTablesToAdd ++ PTables),
3236
named_tables = lists:usort(NamesToAdd ++ NTables)}
3239
filter_named_tables(List) ->
3244
case string:rstr(Head, "()") of
3248
NewHead ++ filter_named_tables(Tail)
3330
3251
races__add_race_warning(Warn, #dialyzer_races{race_warnings = Warns} = Races) ->
3331
3252
Races#dialyzer_races{race_warnings = [Warn|Warns]}.
3333
races__check_module_local_calls(CurrFunLabel, CurrFun, ModuleLocalCalls) ->
3334
case races__check_module_local_calls_helper(CurrFunLabel, CurrFun,
3335
ModuleLocalCalls) of
3337
true -> [{CurrFunLabel, empty, [], processing}]
3340
races__check_module_local_calls_helper(CurrFunLabel, CurrFun,
3341
ModuleLocalCalls) ->
3342
case ModuleLocalCalls of
3346
{CurrFun, _IntA, _TupleB, _IntB, _ArgsB, _CodeA, _CodeB, _Bool} ->
3348
{_TupleA, _IntA, CurrFun, _IntB, _ArgsB, _CodeA, _CodeB, _Bool} ->
3351
races__check_module_local_calls_helper(CurrFunLabel, CurrFun, Tail)
3355
races__get_race_warn(Fun, Args, ArgTypes, DependencyList, State) ->
3254
get_race_warn(Fun, Args, ArgTypes, DependencyList, State) ->
3356
3255
case state__lookup_name(Fun, State) of
3358
{State, {possible_race, [M, F, format_args(Args, ArgTypes, State),
3257
{State, {possible_race, [M, F, Args, ArgTypes, State, DependencyList]}};
3360
3258
Label when is_integer(Label) ->
3364
races__get_race_warnings(#dialyzer_races{race_warnings = RaceWarnings},
3366
races__get_race_warnings_helper(RaceWarnings, State).
3262
get_race_warnings(#dialyzer_races{race_warnings = RaceWarnings}, State) ->
3263
get_race_warnings_helper(RaceWarnings, State).
3368
races__get_race_warnings_helper(Warnings, #state{races = Races} = State) ->
3265
get_race_warnings_helper(Warnings, #state{callgraph = Callgraph,
3266
races = Races} = State) ->
3369
3267
case Warnings of
3370
3268
[] -> {Races, State};
3372
{RaceWarnTag, FileLine, {possible_race, [M, F, A, DepList]}} = H,
3270
{RaceWarnTag, FileLine, {possible_race, [M, F, A, AT, S, DepList]}} = H,
3374
3272
case RaceWarnTag of
3375
3273
?WARN_WHEREIS_REGISTER ->
3376
races__get_reason(lists:keysort(6, DepList),
3274
{get_reason(lists:keysort(6, DepList),
3377
3275
"might fail due to a possible race condition "
3378
"caused by its combination with ");
3276
"caused by its combination with "), true};
3379
3277
?WARN_ETS_LOOKUP_INSERT ->
3380
races__get_reason(lists:keysort(6, DepList),
3381
"might have an unintended effect due to a possible race condition" " caused by its combination with ")
3383
W = {?WARN_POSSIBLE_RACE, FileLine, {possible_race, [M, F, A, Reason]}},
3384
State1 = state__add_warning(W, State),
3385
races__get_race_warnings_helper(T, State1)
3278
InsertList = dialyzer_races:format_args(A, AT, S, ets_insert),
3279
Var = lists:nth(1, InsertList),
3280
Names = lists:nth(2, InsertList),
3281
case dialyzer_races:compare_var_list(Var,
3282
Callgraph#dialyzer_callgraph.public_tables,
3283
Callgraph#dialyzer_callgraph.race_var_map) orelse
3284
length(Names -- Callgraph#dialyzer_callgraph.named_tables) <
3287
{get_reason(lists:keysort(6, DepList),
3288
"might have an unintended effect due to " ++
3289
"a possible race condition " ++
3290
"caused by its combination with "), true};
3291
false -> {"", false}
3298
{?WARN_POSSIBLE_RACE, FileLine,
3299
{possible_race, [M, F, format_args(A, AT, S), Reason]}},
3300
state__add_warning(W, State);
3303
get_race_warnings_helper(T, State1)
3388
races__get_reason(DependencyList, Reason) ->
3306
get_reason(DependencyList, Reason) ->
3389
3307
case DependencyList of
3391
[{Call, _List, ArgTypes, Args, State, {File, Line}}|T] ->
3309
[#dep_call{call_name = Call, arg_types = ArgTypes, vars = Args,
3310
state = State, file_line = {File, Line}}|T] ->