diff options
author | Erlang/OTP <[email protected]> | 2010-02-17 15:48:13 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2010-02-17 15:48:13 +0000 |
commit | 8b39d0582bee5d4071b7ae4c7407d6662c0414a9 (patch) | |
tree | 75b0787b36ae39f477c46e8daadfdf2647b93a1a /lib/dialyzer/src/dialyzer_races.erl | |
parent | edac07ff1e8b49a1ddfd69c712fb2ab3ce37b5ab (diff) | |
parent | abe48c24c115fd629063653eef7bdabd0f82fbbc (diff) | |
download | otp-8b39d0582bee5d4071b7ae4c7407d6662c0414a9.tar.gz otp-8b39d0582bee5d4071b7ae4c7407d6662c0414a9.tar.bz2 otp-8b39d0582bee5d4071b7ae4c7407d6662c0414a9.zip |
Merge branch 'ks/hipe' into ccase/r13b04_dev
* ks/hipe:
dialyzer: Fix system_limit exception in race analysis
syntax_tools: Add types and specs for most exported functions
syntax_tools: Support the --enable-native-libs configure option
syntax_tools: Remove $Id$ annotations
dialyzer: New version for the R13B04 release
hipe: Miscellaneous additions
typer: New version for the R13B04 release
Fix a HiPE compiler bug evaluating an expression that throws system_limit
OTP-8460 ks/hipe
Diffstat (limited to 'lib/dialyzer/src/dialyzer_races.erl')
-rw-r--r-- | lib/dialyzer/src/dialyzer_races.erl | 175 |
1 files changed, 123 insertions, 52 deletions
diff --git a/lib/dialyzer/src/dialyzer_races.erl b/lib/dialyzer/src/dialyzer_races.erl index 5857f7a03d..4972967960 100644 --- a/lib/dialyzer/src/dialyzer_races.erl +++ b/lib/dialyzer/src/dialyzer_races.erl @@ -1,20 +1,20 @@ %% -*- erlang-indent-level: 2 -*- %%----------------------------------------------------------------------- %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -50,8 +50,10 @@ -define(local, 5). -define(no_arg, no_arg). -define(no_label, no_label). +-define(bypassed, bypassed). -define(WARN_WHEREIS_REGISTER, warn_whereis_register). +-define(WARN_WHEREIS_UNREGISTER, warn_whereis_unregister). -define(WARN_ETS_LOOKUP_INSERT, warn_ets_lookup_insert). -define(WARN_MNESIA_DIRTY_READ_WRITE, warn_mnesia_dirty_read_write). -define(WARN_NO_WARN, warn_no_warn). @@ -64,27 +66,29 @@ -type mfa_or_funlbl() :: label() | mfa(). --type label_type() :: label() | [label()] | {label()} | ?no_label. --type args() :: [label_type() | [string()]]. --type core_vars() :: cerl:cerl() | ?no_arg. --type var_to_map() :: core_vars() | [cerl:cerl()]. --type core_args() :: [core_vars()] | 'empty'. --type op() :: 'bind' | 'unbind'. +-type label_type() :: label() | [label()] | {label()} | ?no_label. +-type args() :: [label_type() | [string()]]. +-type core_vars() :: cerl:cerl() | ?no_arg | ?bypassed. +-type var_to_map1() :: core_vars() | [cerl:cerl()]. +-type var_to_map2() :: cerl:cerl() | [cerl:cerl()] | ?bypassed. +-type core_args() :: [core_vars()] | 'empty'. +-type op() :: 'bind' | 'unbind'. -type dep_calls() :: 'whereis' | 'ets_lookup' | 'mnesia_dirty_read'. --type warn_calls() :: 'register' | 'ets_insert' | 'mnesia_dirty_write'. --type call() :: 'whereis' | 'register' | 'ets_new' | 'ets_lookup' - | 'ets_insert' | 'mnesia_dirty_read1' +-type warn_calls() :: 'register' | 'unregister' | 'ets_insert' + | 'mnesia_dirty_write'. +-type call() :: 'whereis' | 'register' | 'unregister' | 'ets_new' + | 'ets_lookup' | 'ets_insert' | 'mnesia_dirty_read1' | 'mnesia_dirty_read2' | 'mnesia_dirty_write1' | 'mnesia_dirty_write2' | 'function_call'. --type race_tag() :: 'whereis_register' | 'ets_lookup_insert' - | 'mnesia_dirty_read_write'. +-type race_tag() :: 'whereis_register' | 'whereis_unregister' + | 'ets_lookup_insert' | 'mnesia_dirty_read_write'. --record(beg_clause, {arg :: var_to_map(), - pats :: var_to_map(), +-record(beg_clause, {arg :: var_to_map1(), + pats :: var_to_map1(), guard :: cerl:cerl()}). --record(end_clause, {arg :: var_to_map(), - pats :: var_to_map(), +-record(end_clause, {arg :: var_to_map1(), + pats :: var_to_map1(), guard :: cerl:cerl()}). -record(end_case, {clauses :: [#end_clause{}]}). -record(curr_fun, {status :: 'in' | 'out', @@ -98,15 +102,15 @@ args :: args(), arg_types :: [erl_types:erl_type()], vars :: [core_vars()], - state :: _, + state :: _, %% XXX: recursive file_line :: file_line(), var_map :: dict()}). -record(fun_call, {caller :: mfa_or_funlbl(), callee :: mfa_or_funlbl(), arg_types :: [erl_types:erl_type()], vars :: [core_vars()]}). --record(let_tag, {var :: var_to_map(), - arg :: var_to_map()}). +-record(let_tag, {var :: var_to_map1(), + arg :: var_to_map1()}). -record(warn_call, {call_name :: warn_calls(), args :: args(), var_map :: dict()}). @@ -180,6 +184,14 @@ store_race_call(Fun, ArgTypes, Args, FileLine, State) -> fun_mfa = CurrFun, fun_label = CurrFunLabel}, {[#warn_call{call_name = register, args = VarArgs}| RaceList], RaceListSize + 1, [RaceFun|RaceTags], no_t}; + {erlang, unregister, 1} -> + VarArgs = format_args(Args, ArgTypes, CleanState, unregister), + RaceFun = #race_fun{mfa = Fun, args = VarArgs, + arg_types = ArgTypes, vars = Args, + file_line = FileLine, index = RaceListSize, + fun_mfa = CurrFun, fun_label = CurrFunLabel}, + {[#warn_call{call_name = unregister, args = VarArgs}| + RaceList], RaceListSize + 1, [RaceFun|RaceTags], no_t}; {erlang, whereis, 1} -> VarArgs = format_args(Args, ArgTypes, CleanState, whereis), {[#dep_call{call_name = whereis, args = VarArgs, @@ -280,6 +292,7 @@ race(State) -> RaceWarnTag = case Fun of {erlang, register, 2} -> ?WARN_WHEREIS_REGISTER; + {erlang, unregister, 1} -> ?WARN_WHEREIS_UNREGISTER; {ets, insert, 2} -> ?WARN_ETS_LOOKUP_INSERT; {mnesia, dirty_write, _A} -> ?WARN_MNESIA_DIRTY_READ_WRITE end, @@ -287,7 +300,7 @@ race(State) -> state__renew_curr_fun(CurrFun, state__renew_curr_fun_label(CurrFunLabel, state__renew_race_list(lists:nthtail(length(RaceList) - Index, - RaceList), State))), + RaceList), State))), DepList = fixup_race_list(RaceWarnTag, VarArgs, State1), {State2, RaceWarn} = get_race_warn(Fun, Args, ArgTypes, DepList, State), @@ -309,6 +322,7 @@ fixup_race_list(RaceWarnTag, WarnVarArgs, State) -> RaceTag = case RaceWarnTag of ?WARN_WHEREIS_REGISTER -> whereis_register; + ?WARN_WHEREIS_UNREGISTER -> whereis_unregister; ?WARN_ETS_LOOKUP_INSERT -> ets_lookup_insert; ?WARN_MNESIA_DIRTY_READ_WRITE -> mnesia_dirty_read_write end, @@ -320,11 +334,9 @@ fixup_race_list(RaceWarnTag, WarnVarArgs, State) -> lists:reverse(NewRaceList), [], CurrFun, WarnVarArgs, RaceWarnTag, dict:new(), [], [], [], 2 * ?local, NewState), - Parents = - fixup_race_backward(CurrFun, Calls, Calls, [], ?local), + Parents = fixup_race_backward(CurrFun, Calls, Calls, [], ?local), UParents = lists:usort(Parents), - Filtered = - filter_parents(UParents, UParents, Digraph), + Filtered = filter_parents(UParents, UParents, Digraph), NewParents = case lists:member(CurrFun, Filtered) of true -> Filtered; @@ -401,8 +413,7 @@ fixup_race_forward_pullout(CurrFun, CurrFunLabel, Calls, Code, RaceList, false -> {ok, Fun} = Name, {ok, Int} = Label, - case dict:find(Fun, - dialyzer_callgraph:get_race_code(Callgraph)) of + case dict:find(Fun, dialyzer_callgraph:get_race_code(Callgraph)) of error -> {NewCurrFun, NewCurrFunLabel, NewCalls, Tail, NewRaceList, NewRaceVarMap, NewFunDefVars, NewFunCallVars, NewFunArgTypes, @@ -459,7 +470,8 @@ fixup_race_forward(CurrFun, CurrFunLabel, Calls, Code, RaceList, case Head of #dep_call{call_name = whereis} -> case RaceWarnTag of - ?WARN_WHEREIS_REGISTER -> + WarnWhereis when WarnWhereis =:= ?WARN_WHEREIS_REGISTER orelse + WarnWhereis =:= ?WARN_WHEREIS_UNREGISTER -> {[Head#dep_call{var_map = RaceVarMap}|RaceList], [], NestingLevel, false}; _Other -> @@ -493,9 +505,11 @@ fixup_race_forward(CurrFun, CurrFunLabel, Calls, Code, RaceList, _Other -> {RaceList, [], NestingLevel, false} end; - #warn_call{call_name = register} -> + #warn_call{call_name = RegCall} when RegCall =:= register orelse + RegCall =:= unregister -> case RaceWarnTag of - ?WARN_WHEREIS_REGISTER -> + WarnWhereis when WarnWhereis =:= ?WARN_WHEREIS_REGISTER orelse + WarnWhereis =:= ?WARN_WHEREIS_UNREGISTER -> {[Head#warn_call{var_map = RaceVarMap}|RaceList], [], NestingLevel, false}; _Other -> @@ -575,6 +589,10 @@ fixup_race_forward(CurrFun, CurrFunLabel, Calls, Code, RaceList, {[#warn_call{call_name = register, args = WarnVarArgs, var_map = RaceVarMap}], NewDepList}; + whereis_unregister -> + {[#warn_call{call_name = unregister, args = WarnVarArgs, + var_map = RaceVarMap}], + NewDepList}; ets_lookup_insert -> NewWarnCall = [#warn_call{call_name = ets_insert, args = WarnVarArgs, @@ -760,6 +778,19 @@ get_deplist_paths(RaceList, WarnVarArgs, RaceWarnTag, RaceVarMap, CurrLevel, _ -> {[Vars, WVA2, WVA3, WVA4], false} end; + ?WARN_WHEREIS_UNREGISTER -> + [WVA1, WVA2] = WarnVarArgs1, + Vars = + lists:flatten( + [find_all_bound_vars(V, RaceVarMap1) || V <- WVA1]), + case {Vars, CurrLevel} of + {[], 0} -> + {WarnVarArgs, true}; + {[], _} -> + {WarnVarArgs, false}; + _ -> + {[Vars, WVA2], false} + end; ?WARN_ETS_LOOKUP_INSERT -> [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs1, Vars1 = @@ -805,8 +836,9 @@ get_deplist_paths(RaceList, WarnVarArgs, RaceWarnTag, RaceVarMap, CurrLevel, get_deplist_paths(Tail, WarnVarArgs2, RaceWarnTag, RaceVarMap1, CurrLevel1, PublicTables, NamedTables) end; - #warn_call{call_name = register, args = WarnVarArgs1, - var_map = RaceVarMap1} -> + #warn_call{call_name = RegCall, args = WarnVarArgs1, + var_map = RaceVarMap1} when RegCall =:= register orelse + RegCall =:= unregister -> case compare_first_arg(WarnVarArgs, WarnVarArgs1, RaceVarMap1) of true -> {[], false, false}; NewWarnVarArgs -> @@ -1416,7 +1448,8 @@ lists_get(N, List) -> lists:nth(N, List). refine_race(RaceCall, WarnVarArgs, RaceWarnTag, DependencyList, RaceVarMap) -> case RaceWarnTag of - ?WARN_WHEREIS_REGISTER -> + WarnWhereis when WarnWhereis =:= ?WARN_WHEREIS_REGISTER orelse + WarnWhereis =:= ?WARN_WHEREIS_UNREGISTER -> case RaceCall of #dep_call{call_name = ets_lookup} -> DependencyList; @@ -1660,6 +1693,20 @@ compare_types(VarArgs, WarnVarArgs, RaceWarnTag, RaceVarMap) -> end end; + ?WARN_WHEREIS_UNREGISTER -> + [VA1, VA2] = VarArgs, + [WVA1, WVA2] = WarnVarArgs, + case any_args(VA2) of + true -> compare_var_list(VA1, WVA1, RaceVarMap); + false -> + case any_args(WVA2) of + true -> compare_var_list(VA1, WVA1, RaceVarMap); + false -> + compare_var_list(VA1, WVA1, RaceVarMap) orelse + compare_argtypes(VA2, WVA2) + + end + end; ?WARN_ETS_LOOKUP_INSERT -> [VA1, VA2, VA3, VA4] = VarArgs, [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs, @@ -1683,8 +1730,8 @@ compare_types(VarArgs, WarnVarArgs, RaceWarnTag, RaceVarMap) -> true -> compare_var_list(VA3, WVA3, RaceVarMap); false -> - compare_var_list(VA3, WVA3, RaceVarMap) - orelse compare_argtypes(VA4, WVA4) + compare_var_list(VA3, WVA3, RaceVarMap) orelse + compare_argtypes(VA4, WVA4) end end); ?WARN_MNESIA_DIRTY_READ_WRITE -> @@ -1818,6 +1865,7 @@ ets_tuple_argtypes1(Str, Tuple, TupleList, NestingLevel) -> end end. +format_arg(?bypassed) -> ?no_label; format_arg(Arg) -> case cerl:type(Arg) of var -> cerl_trees:get_label(Arg); @@ -1845,9 +1893,13 @@ format_args_1([Arg], [Type], CleanState) -> [format_arg(Arg), format_type(Type, CleanState)]; format_args_1([Arg|Args], [Type|Types], CleanState) -> List = - case cerl:is_literal(Arg) of - true -> [?no_label, format_cerl(Arg)]; - false -> [format_arg(Arg), format_type(Type, CleanState)] + case Arg =:= ?bypassed of + true -> [?no_label, format_type(Type, CleanState)]; + false -> + case cerl:is_literal(Arg) of + true -> [?no_label, format_cerl(Arg)]; + false -> [format_arg(Arg), format_type(Type, CleanState)] + end end, List ++ format_args_1(Args, Types, CleanState). @@ -1859,6 +1911,9 @@ format_args_2(StrArgList, Call) -> register -> lists_key_replace(2, StrArgList, string:tokens(lists:nth(2, StrArgList), " |")); + unregister -> + lists_key_replace(2, StrArgList, + string:tokens(lists:nth(2, StrArgList), " |")); ets_new -> StrArgList1 = lists_key_replace(2, StrArgList, string:tokens(lists:nth(2, StrArgList), " |")), @@ -1919,10 +1974,11 @@ mnesia_tuple_argtypes(TupleStr) -> [TupleStr2|_T] = string:tokens(TupleStr1, " ,"), lists:flatten(string:tokens(TupleStr2, " |")). --spec race_var_map(var_to_map(), cerl:cerl() | [cerl:cerl()], dict(), op()) -> dict(). +-spec race_var_map(var_to_map1(), var_to_map2(), dict(), op()) -> dict(). race_var_map(Vars1, Vars2, RaceVarMap, Op) -> - case Vars1 =:= ?no_arg of + case Vars1 =:= ?no_arg orelse Vars1 =:= ?bypassed + orelse Vars2 =:= ?bypassed of true -> RaceVarMap; false -> case is_list(Vars1) andalso is_list(Vars2) of @@ -2076,7 +2132,7 @@ race_var_map_guard(Arg, Pats, Guard, RaceVarMap, Op) -> {RaceVarMap1, RemoveClause orelse RemoveClause1}. race_var_map_guard_helper1(Arg, Pats, RaceVarMap, Op) -> - case Arg =:= ?no_arg of + case Arg =:= ?no_arg orelse Arg =:= ?bypassed of true -> {RaceVarMap, false}; false -> case cerl:type(Arg) of @@ -2139,7 +2195,7 @@ unbind_dict_vars(Var1, Var2, RaceVarMap) -> true -> unbind_dict_vars(Var1, Var2, bind_dict_vars_list(Var1, Labels -- [Var2], - dict:erase(Var1, RaceVarMap))); + dict:erase(Var1, RaceVarMap))); false -> unbind_dict_vars_helper(Labels, Var1, Var2, RaceVarMap) end @@ -2171,6 +2227,10 @@ var_analysis(FunDefArgs, FunCallArgs, WarnVarArgs, RaceWarnTag) -> [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs, ArgNos = lists_key_members_lists(WVA1, FunDefArgs), [[lists_get(N, FunCallArgs) || N <- ArgNos], WVA2, WVA3, WVA4]; + ?WARN_WHEREIS_UNREGISTER -> + [WVA1, WVA2] = WarnVarArgs, + ArgNos = lists_key_members_lists(WVA1, FunDefArgs), + [[lists_get(N, FunCallArgs) || N <- ArgNos], WVA2]; ?WARN_ETS_LOOKUP_INSERT -> [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs, ArgNos1 = lists_key_members_lists(WVA1, FunDefArgs), @@ -2185,8 +2245,7 @@ var_analysis(FunDefArgs, FunCallArgs, WarnVarArgs, RaceWarnTag) -> var_type_analysis(FunDefArgs, FunCallTypes, WarnVarArgs, RaceWarnTag, RaceVarMap, CleanState) -> - FunVarArgs = format_args(FunDefArgs, FunCallTypes, CleanState, - function_call), + FunVarArgs = format_args(FunDefArgs, FunCallTypes, CleanState, function_call), case RaceWarnTag of ?WARN_WHEREIS_REGISTER -> [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs, @@ -2197,6 +2256,15 @@ var_type_analysis(FunDefArgs, FunCallTypes, WarnVarArgs, RaceWarnTag, NewWVA2 = string:tokens(lists:nth(N + 1, FunVarArgs), " |"), [Vars, NewWVA2, WVA3, WVA4] end; + ?WARN_WHEREIS_UNREGISTER -> + [WVA1, WVA2] = WarnVarArgs, + Vars = find_all_bound_vars(WVA1, RaceVarMap), + case lists_key_member_lists(Vars, FunVarArgs) of + 0 -> [Vars, WVA2]; + N when is_integer(N) -> + NewWVA2 = string:tokens(lists:nth(N + 1, FunVarArgs), " |"), + [Vars, NewWVA2] + end; ?WARN_ETS_LOOKUP_INSERT -> [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs, Vars1 = find_all_bound_vars(WVA1, RaceVarMap), @@ -2278,6 +2346,10 @@ get_race_warnings_helper(Warnings, State) -> get_reason(lists:keysort(7, DepList), "might fail due to a possible race condition " "caused by its combination with "); + ?WARN_WHEREIS_UNREGISTER -> + get_reason(lists:keysort(7, DepList), + "might fail due to a possible race condition " + "caused by its combination with "); ?WARN_ETS_LOOKUP_INSERT -> get_reason(lists:keysort(7, DepList), "might have an unintended effect due to " ++ @@ -2335,7 +2407,7 @@ state__add_race_warning(State, RaceWarn, RaceWarnTag, FileLine) -> %%% %%% =========================================================================== --spec beg_clause_new(var_to_map(), var_to_map(), cerl:cerl()) -> +-spec beg_clause_new(var_to_map1(), var_to_map1(), cerl:cerl()) -> #beg_clause{}. beg_clause_new(Arg, Pats, Guard) -> @@ -2351,7 +2423,7 @@ cleanup(#races{race_list = RaceList}) -> end_case_new(Clauses) -> #end_case{clauses = Clauses}. --spec end_clause_new(var_to_map(), var_to_map(), cerl:cerl()) -> +-spec end_clause_new(var_to_map1(), var_to_map1(), cerl:cerl()) -> #end_clause{}. end_clause_new(Arg, Pats, Guard) -> @@ -2387,7 +2459,7 @@ get_race_list(#races{race_list = RaceList}) -> get_race_list_size(#races{race_list_size = RaceListSize}) -> RaceListSize. --spec let_tag_new(var_to_map(), var_to_map()) -> #let_tag{}. +-spec let_tag_new(var_to_map1(), var_to_map1()) -> #let_tag{}. let_tag_new(Var, Arg) -> #let_tag{var = Var, arg = Arg}. @@ -2422,5 +2494,4 @@ put_race_analysis(Analysis, Races) -> races(). put_race_list(RaceList, RaceListSize, Races) -> - Races#races{race_list = RaceList, - race_list_size = RaceListSize}. + Races#races{race_list = RaceList, race_list_size = RaceListSize}. |