~ubuntu-branches/ubuntu/trusty/erlang/trusty

« back to all changes in this revision

Viewing changes to lib/dialyzer/src/dialyzer_races.erl

  • Committer: Bazaar Package Importer
  • Author(s): Clint Byrum
  • Date: 2011-05-05 15:48:43 UTC
  • mfrom: (3.5.13 sid)
  • Revision ID: james.westby@ubuntu.com-20110505154843-0om6ekzg6m7ugj27
Tags: 1:14.b.2-dfsg-3ubuntu1
* Merge from debian unstable.  Remaining changes:
  - Drop libwxgtk2.8-dev build dependency. Wx isn't in main, and not
    supposed to.
  - Drop erlang-wx binary.
  - Drop erlang-wx dependency from -megaco, -common-test, and -reltool, they
    do not really need wx. Also drop it from -debugger; the GUI needs wx,
    but it apparently has CLI bits as well, and is also needed by -megaco,
    so let's keep the package for now.
  - debian/patches/series: Do what I meant, and enable build-options.patch
    instead.
* Additional changes:
  - Drop erlang-wx from -et
* Dropped Changes:
  - patches/pcre-crash.patch: CVE-2008-2371: outer level option with
    alternatives caused crash. (Applied Upstream)
  - fix for ssl certificate verification in newSSL: 
    ssl_cacertfile_fix.patch (Applied Upstream)
  - debian/patches/series: Enable native.patch again, to get stripped beam
    files and reduce the package size again. (build-options is what
    actually accomplished this)
  - Remove build-options.patch on advice from upstream and because it caused
    odd build failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
%% -*- erlang-indent-level: 2 -*-
2
2
%%-----------------------------------------------------------------------
3
3
%% %CopyrightBegin%
4
 
%% 
5
 
%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
6
 
%% 
 
4
%%
 
5
%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
 
6
%%
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/.
12
 
%% 
 
12
%%
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.
17
 
%% 
 
17
%%
18
18
%% %CopyrightEnd%
19
19
%%
20
20
 
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
25
25
%%%
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]).
41
41
 
 
42
-export_type([races/0, mfa_or_funlbl/0, core_vars/0]).
 
43
 
42
44
-include("dialyzer.hrl").
43
45
 
44
46
%%% ===========================================================================
50
52
-define(local, 5).
51
53
-define(no_arg, no_arg).
52
54
-define(no_label, no_label).
 
55
-define(bypassed, bypassed).
53
56
 
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).
64
68
 
65
69
-type mfa_or_funlbl() :: label() | mfa().
66
70
 
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'.
73
78
 
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'.
82
88
 
83
 
-record(beg_clause, {arg        :: var_to_map(),
84
 
                     pats       :: 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(),
87
 
                     pats       :: 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',
98
104
                     args       :: args(),
99
105
                     arg_types  :: [erl_types:erl_type()],
100
106
                     vars       :: [core_vars()],
101
 
                     state      :: _,
 
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(),
111
117
                     args       :: args(),
112
118
                     var_map    :: dict()}).
113
119
 
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()].
117
123
 
118
124
-type table_var()  :: label() | ?no_label.
153
159
%%% ===========================================================================
154
160
 
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().
158
164
 
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} =
166
172
    case CurrFun of
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,
280
294
        RaceWarnTag =
281
295
          case Fun of
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
285
300
          end,
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,
290
 
                                 RaceList), State))),
 
305
                                               RaceList), State))),
291
306
        DepList = fixup_race_list(RaceWarnTag, VarArgs, State1),
292
307
        {State2, RaceWarn} =
293
308
          get_race_warn(Fun, Args, ArgTypes, DepList, State),
309
324
  RaceTag =
310
325
    case RaceWarnTag of
311
326
      ?WARN_WHEREIS_REGISTER -> whereis_register;
 
327
      ?WARN_WHEREIS_UNREGISTER -> whereis_unregister;
312
328
      ?WARN_ETS_LOOKUP_INSERT -> ets_lookup_insert;
313
329
      ?WARN_MNESIA_DIRTY_READ_WRITE -> mnesia_dirty_read_write
314
330
    end,
320
336
                               lists:reverse(NewRaceList), [], CurrFun,
321
337
                               WarnVarArgs, RaceWarnTag, dict:new(),
322
338
                               [], [], [], 2 * ?local, NewState),
323
 
  Parents =
324
 
    fixup_race_backward(CurrFun, Calls, Calls, [], ?local),
 
339
  Parents = fixup_race_backward(CurrFun, Calls, Calls, [], ?local),
325
340
  UParents = lists:usort(Parents),
326
 
  Filtered =
327
 
    filter_parents(UParents, UParents, Digraph),
 
341
  Filtered = filter_parents(UParents, UParents, Digraph),
328
342
  NewParents =
329
343
    case lists:member(CurrFun, Filtered) of
330
344
      true -> Filtered;
401
415
          false ->
402
416
            {ok, Fun} = Name,
403
417
            {ok, Int} = Label,
404
 
            case dict:find(Fun,
405
 
                   dialyzer_callgraph:get_race_code(Callgraph)) of
 
418
            case dict:find(Fun, dialyzer_callgraph:get_race_code(Callgraph)) of
406
419
              error ->
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,
459
472
        case Head of
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};
465
479
              _Other ->
466
480
                {RaceList, [], NestingLevel, false}
467
481
            end;
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),
474
 
                  RaceVarMap)
475
 
                  orelse
476
 
                  length(Names --
477
 
                  dialyzer_callgraph:get_named_tables(Callgraph)) <
478
 
                  length(Names) of
479
 
                  true ->
480
 
                    {[Head#dep_call{var_map = RaceVarMap}|RaceList],
481
 
                     [], NestingLevel, false};
482
 
                  false ->
483
 
                    {RaceList, [], NestingLevel, false}
484
 
                end;
 
485
                {[Head#dep_call{var_map = RaceVarMap}|RaceList],
 
486
                 [], NestingLevel, false};
485
487
              _Other ->
486
488
                {RaceList, [], NestingLevel, false}
487
489
            end;
493
495
              _Other ->
494
496
                {RaceList, [], NestingLevel, false}
495
497
            end;
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};
501
505
              _Other ->
502
506
                {RaceList, [], NestingLevel, false}
503
507
            end;
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),
510
 
                  RaceVarMap)
511
 
                  orelse
512
 
                  length(Names --
513
 
                  dialyzer_callgraph:get_named_tables(Callgraph)) <
514
 
                  length(Names) of
515
 
                  true ->
516
 
                    {[Head#warn_call{var_map = RaceVarMap}|RaceList],
517
 
                     [], NestingLevel, false};
518
 
                  false ->
519
 
                    {RaceList, [], NestingLevel, false}
520
 
                end;
 
511
                {[Head#warn_call{var_map = RaceVarMap}|RaceList],
 
512
                 [], NestingLevel, false};
521
513
              _Other ->
522
514
                {RaceList, [], NestingLevel, false}
523
515
            end;
562
554
          RaceTag ->
563
555
            PublicTables = dialyzer_callgraph:get_public_tables(Callgraph),
564
556
            NamedTables = dialyzer_callgraph:get_named_tables(Callgraph),
565
 
            WarnVarArgs1 = 
 
557
            WarnVarArgs1 =
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}],
577
569
                   NewDepList};
 
570
                 whereis_unregister ->
 
571
                  {[#warn_call{call_name = unregister, args = WarnVarArgs,
 
572
                              var_map = RaceVarMap}],
 
573
                   NewDepList};
578
574
                ets_lookup_insert ->
579
575
                  NewWarnCall =
580
576
                    [#warn_call{call_name = ets_insert, args = WarnVarArgs,
581
577
                                var_map = RaceVarMap}],
582
578
                  [Tab, Names, _, _] = WarnVarArgs,
583
 
                  case IsPublic orelse 
 
579
                  case IsPublic orelse
584
580
                    compare_var_list(Tab, PublicTables, RaceVarMap)
585
581
                    orelse
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};
632
628
              false ->
633
 
                {CurrFun, CurrFunLabel, Tail, NewRL, RaceVarMap1, 
 
629
                {CurrFun, CurrFunLabel, Tail, NewRL, RaceVarMap1,
634
630
                 FunDefVars, FunCallVars, FunArgTypes, NewNL, false}
635
631
            end;
636
632
          #end_clause{arg = Arg, pats = Pats, guard = Guard} ->
760
756
                  _ ->
761
757
                    {[Vars, WVA2, WVA3, WVA4], false}
762
758
                end;
 
759
              ?WARN_WHEREIS_UNREGISTER ->
 
760
                [WVA1, WVA2] = WarnVarArgs1,
 
761
                Vars =
 
762
                  lists:flatten(
 
763
                    [find_all_bound_vars(V, RaceVarMap1) || V <- WVA1]),
 
764
                case {Vars, CurrLevel} of
 
765
                  {[], 0} ->
 
766
                    {WarnVarArgs, true};
 
767
                  {[], _} ->
 
768
                    {WarnVarArgs, false};
 
769
                  _ ->
 
770
                    {[Vars, WVA2], false}
 
771
                end;
763
772
              ?WARN_ETS_LOOKUP_INSERT ->
764
773
                [WVA1, WVA2, WVA3, WVA4] = WarnVarArgs1,
765
774
                Vars1 =
805
814
              get_deplist_paths(Tail, WarnVarArgs2, RaceWarnTag, RaceVarMap1,
806
815
                                CurrLevel1, PublicTables, NamedTables)
807
816
          end;
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}.
867
877
 
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),
1028
1038
  case Height =:= 0 of
1029
1039
    true -> Parents;
1030
1040
    false ->
1031
 
      case Calls of 
 
1041
      case Calls of
1032
1042
        [] ->
1033
1043
          case is_integer(CurrFun) orelse lists:member(CurrFun, Parents) of
1034
1044
            true -> Parents;
1187
1197
callgraph__renew_tables(Table, Callgraph) ->
1188
1198
  case Table of
1189
1199
    {named, NameLabel, Names} ->
1190
 
      PTablesToAdd = 
 
1200
      PTablesToAdd =
1191
1201
        case NameLabel of
1192
1202
          ?no_label -> [];
1193
1203
          _Other -> [NameLabel]
1406
1416
  end;
1407
1417
lists_key_members_lists_helper(_Elem, _List, _N) ->
1408
1418
  [0].
1409
 
          
 
1419
 
1410
1420
lists_key_replace(N, List, NewMember) ->
1411
1421
  {Before, [_|After]} = lists:split(N - 1, List),
1412
1422
  Before ++ [NewMember|After].
1416
1426
 
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
1456
1467
  end.
1457
1468
 
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),
1588
1599
        end
1589
1600
    end,
1590
1601
  case Bool of
1591
 
    true -> 
 
1602
    true ->
1592
1603
      case any_args(Old4) of
1593
1604
        true ->
1594
1605
          case compare_list_vars(Old3, ets_list_args(New3), [], RaceVarMap) of
1657
1668
            false ->
1658
1669
              compare_var_list(VA1, WVA1, RaceVarMap) orelse
1659
1670
                compare_argtypes(VA2, WVA2)
1660
 
                
 
1671
          end
 
1672
      end;
 
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);
 
1678
        false ->
 
1679
          case any_args(WVA2) of
 
1680
            true -> compare_var_list(VA1, WVA1, RaceVarMap);
 
1681
            false ->
 
1682
              compare_var_list(VA1, WVA1, RaceVarMap) orelse
 
1683
                compare_argtypes(VA2, WVA2)
1661
1684
          end
1662
1685
      end;
1663
1686
    ?WARN_ETS_LOOKUP_INSERT ->
1669
1692
          false ->
1670
1693
            case any_args(WVA2) of
1671
1694
              true -> compare_var_list(VA1, WVA1, RaceVarMap);
1672
 
              false -> 
 
1695
              false ->
1673
1696
                compare_var_list(VA1, WVA1, RaceVarMap) orelse
1674
1697
                  compare_argtypes(VA2, WVA2)
1675
1698
            end
1676
1699
        end,
1677
 
      Bool andalso  
 
1700
      Bool andalso
1678
1701
        (case any_args(VA4) of
1679
1702
           true ->
1680
1703
             compare_var_list(VA3, WVA3, RaceVarMap);
1683
1706
               true ->
1684
1707
                 compare_var_list(VA3, WVA3, RaceVarMap);
1685
1708
               false ->
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)
1688
1711
             end
1689
1712
         end);
1690
1713
    ?WARN_MNESIA_DIRTY_READ_WRITE ->
1818
1841
        end
1819
1842
  end.
1820
1843
 
 
1844
format_arg(?bypassed) -> ?no_label;
1821
1845
format_arg(Arg) ->
1822
1846
  case cerl:type(Arg) of
1823
1847
    var -> cerl_trees:get_label(Arg);
1845
1869
  [format_arg(Arg), format_type(Type, CleanState)];
1846
1870
format_args_1([Arg|Args], [Type|Types], CleanState) ->
1847
1871
  List =
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)];
 
1874
      false ->
 
1875
        case cerl:is_literal(Arg) of
 
1876
          true -> [?no_label, format_cerl(Arg)];
 
1877
          false -> [format_arg(Arg), format_type(Type, CleanState)]
 
1878
        end
1851
1879
    end,
1852
1880
  List ++ format_args_1(Args, Types, CleanState).
1853
1881
 
1859
1887
    register ->
1860
1888
      lists_key_replace(2, StrArgList,
1861
1889
        string:tokens(lists:nth(2, StrArgList), " |"));
 
1890
    unregister ->
 
1891
      lists_key_replace(2, StrArgList,
 
1892
        string:tokens(lists:nth(2, StrArgList), " |"));
1862
1893
    ets_new ->
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, " |")).
1921
1952
 
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().
1923
1954
 
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;
1927
1959
    false ->
1928
1960
      case is_list(Vars1) andalso is_list(Vars2) of
2076
2108
  {RaceVarMap1, RemoveClause orelse RemoveClause1}.
2077
2109
 
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};
2081
2113
    false ->
2082
2114
      case cerl:type(Arg) of
2102
2134
                    _Else -> {RaceVarMap, false}
2103
2135
                  end;
2104
2136
                false -> {RaceVarMap, false}
2105
 
              end;                   
 
2137
              end;
2106
2138
            _Other -> {RaceVarMap, false}
2107
2139
          end;
2108
2140
        _Other -> {RaceVarMap, false}
2139
2171
            true ->
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)));
2143
2175
            false ->
2144
2176
              unbind_dict_vars_helper(Labels, Var1, Var2, RaceVarMap)
2145
2177
          end
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]
2184
 
  end.     
 
2220
  end.
2185
2221
 
2186
2222
var_type_analysis(FunDefArgs, FunCallTypes, WarnVarArgs, RaceWarnTag,
2187
2223
                  RaceVarMap, CleanState) ->
2188
 
  FunVarArgs = format_args(FunDefArgs, FunCallTypes, CleanState,
2189
 
                           function_call),
 
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]
2199
2234
      end;
 
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
 
2239
        0 -> [Vars, WVA2];
 
2240
        N when is_integer(N) ->
 
2241
          NewWVA2 = string:tokens(lists:nth(N + 1, FunVarArgs), " |"),
 
2242
          [Vars, NewWVA2]
 
2243
      end;
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),
2219
2263
            []),
2220
2264
          FirstVarArg ++ [Vars2, NewWVA4]
2221
 
          
 
2265
 
2222
2266
      end;
2223
2267
    ?WARN_MNESIA_DIRTY_READ_WRITE ->
2224
2268
      [WVA1, WVA2|T] = WarnVarArgs,
2262
2306
 
2263
2307
-spec get_race_warnings(races(), dialyzer_dataflow:state()) ->
2264
2308
  {races(), dialyzer_dataflow:state()}.
2265
 
  
 
2309
 
2266
2310
get_race_warnings(#races{race_warnings = RaceWarnings}, State) ->
2267
2311
  get_race_warnings_helper(RaceWarnings, State).
2268
2312
 
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 " ++
2335
2383
%%%
2336
2384
%%% ===========================================================================
2337
2385
 
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()) ->
2339
2387
   #beg_clause{}.
2340
2388
 
2341
2389
beg_clause_new(Arg, Pats, Guard) ->
2351
2399
end_case_new(Clauses) ->
2352
2400
  #end_case{clauses = Clauses}.
2353
2401
 
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()) ->
2355
2403
   #end_clause{}.
2356
2404
 
2357
2405
end_clause_new(Arg, Pats, Guard) ->
2358
2406
  #end_clause{arg = Arg, pats = Pats, guard = Guard}.
2359
2407
 
2360
2408
-spec get_curr_fun(races()) -> mfa_or_funlbl().
2361
 
  
 
2409
 
2362
2410
get_curr_fun(#races{curr_fun = CurrFun}) ->
2363
2411
  CurrFun.
2364
2412
 
2365
2413
-spec get_curr_fun_args(races()) -> core_args().
2366
 
  
 
2414
 
2367
2415
get_curr_fun_args(#races{curr_fun_args = CurrFunArgs}) ->
2368
2416
  CurrFunArgs.
2369
2417
 
2373
2421
  Table.
2374
2422
 
2375
2423
-spec get_race_analysis(races()) -> boolean().
2376
 
  
 
2424
 
2377
2425
get_race_analysis(#races{race_analysis = RaceAnalysis}) ->
2378
2426
  RaceAnalysis.
2379
2427
 
2380
2428
-spec get_race_list(races()) -> code().
2381
 
  
 
2429
 
2382
2430
get_race_list(#races{race_list = RaceList}) ->
2383
2431
  RaceList.
2384
2432
 
2385
2433
-spec get_race_list_size(races()) -> non_neg_integer().
2386
 
  
 
2434
 
2387
2435
get_race_list_size(#races{race_list_size = RaceListSize}) ->
2388
2436
  RaceListSize.
2389
2437
 
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{}.
2391
2439
 
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
2413
2461
  end.
2414
 
  
 
2462
 
2415
2463
-spec put_race_analysis(boolean(), races()) ->
2416
2464
  races().
2417
 
  
 
2465
 
2418
2466
put_race_analysis(Analysis, Races) ->
2419
2467
  Races#races{race_analysis = Analysis}.
2420
2468
 
2422
2470
  races().
2423
2471
 
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}.