@ -384,295 +384,283 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
 
			
		
	
		
			
				
					    |  _  -> 
 
			
		
	
		
			
				
					        false 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  let  exec_instr  ( astate  :  Domain . astate )  ( {  ProcData . extras ;  tenv ;  pdesc ;  }  as  proc_data )  _  instr  = 
 
			
		
	
		
			
				
					  let  add_reads  exps  loc  accesses  locks  attribute_map  proc_data  = 
 
			
		
	
		
			
				
					    List . fold 
 
			
		
	
		
			
				
					      ~ f : ( fun  acc  exp  ->  add_access  exp  loc  Read  acc  locks  attribute_map  proc_data ) 
 
			
		
	
		
			
				
					      exps 
 
			
		
	
		
			
				
					      ~ init : accesses 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					  let  exec_instr 
 
			
		
	
		
			
				
					      ( astate  :  Domain . astate ) 
 
			
		
	
		
			
				
					      ( {  ProcData . extras ;  tenv ;  pdesc ;  }  as  proc_data ) 
 
			
		
	
		
			
				
					      _ 
 
			
		
	
		
			
				
					      ( instr  :  HilInstr . t )  = 
 
			
		
	
		
			
				
					    let  open  Domain  in 
 
			
		
	
		
			
				
					    let  add_reads  exps  loc  accesses  locks  attribute_map  proc_data  = 
 
			
		
	
		
			
				
					      List . fold 
 
			
		
	
		
			
				
					        ~ f : ( fun  acc  exp  ->  add_access  exp  loc  Read  acc  locks  attribute_map  proc_data ) 
 
			
		
	
		
			
				
					        exps 
 
			
		
	
		
			
				
					        ~ init : accesses  in 
 
			
		
	
		
			
				
					    let  exec_instr_  =  function 
 
			
		
	
		
			
				
					      |  HilInstr . Call  ( Some  ret_base ,  Direct  procname ,  actuals ,  _ ,  loc ) 
 
			
		
	
		
			
				
					        when  acquires_ownership  procname  tenv  -> 
 
			
		
	
		
			
				
					          let  accesses  = 
 
			
		
	
		
			
				
					            add_reads  actuals  loc  astate . accesses  astate . locks  astate . attribute_map  proc_data  in 
 
			
		
	
		
			
				
					          let  attribute_map  = 
 
			
		
	
		
			
				
					            AttributeMapDomain . add_attribute 
 
			
		
	
		
			
				
					              ( ret_base ,  [] )  Attribute . unconditionally_owned  astate . attribute_map  in 
 
			
		
	
		
			
				
					          {  astate  with  accesses ;  attribute_map ;  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      |  HilInstr . Call  ( ret_opt ,  Direct  callee_pname ,  actuals ,  call_flags ,  loc )  -> 
 
			
		
	
		
			
				
					          let  accesses  = 
 
			
		
	
		
			
				
					            add_reads  actuals  loc  astate . accesses  astate . locks  astate . attribute_map  proc_data  in 
 
			
		
	
		
			
				
					          let  astate  =  {  astate  with  accesses ;  }  in 
 
			
		
	
		
			
				
					          let  astate_callee  = 
 
			
		
	
		
			
				
					            (*  assuming that modeled procedures do not have useful summaries  *) 
 
			
		
	
		
			
				
					            if  is_thread_utils_method  " assertMainThread "  callee_pname 
 
			
		
	
		
			
				
					            then 
 
			
		
	
		
			
				
					              {  astate  with  threads  =  true ;  } 
 
			
		
	
		
			
				
					            else 
 
			
		
	
		
			
				
					              match  get_lock_model  callee_pname  with 
 
			
		
	
		
			
				
					              |  Lock  -> 
 
			
		
	
		
			
				
					                  {  astate  with  locks  =  true ;  } 
 
			
		
	
		
			
				
					              |  Unlock  -> 
 
			
		
	
		
			
				
					                  {  astate  with  locks  =  false ;  } 
 
			
		
	
		
			
				
					              |  LockedIfTrue  -> 
 
			
		
	
		
			
				
					                  begin 
 
			
		
	
		
			
				
					                    match  ret_opt  with 
 
			
		
	
		
			
				
					                    |  Some  ret_access_path  -> 
 
			
		
	
		
			
				
					                        let  attribute_map  = 
 
			
		
	
		
			
				
					                          AttributeMapDomain . add_attribute 
 
			
		
	
		
			
				
					                            ( ret_access_path ,  [] ) 
 
			
		
	
		
			
				
					                            ( Choice  Choice . LockHeld ) 
 
			
		
	
		
			
				
					                            astate . attribute_map  in 
 
			
		
	
		
			
				
					                        {  astate  with  attribute_map ;  } 
 
			
		
	
		
			
				
					                    |  None  -> 
 
			
		
	
		
			
				
					                        failwithf 
 
			
		
	
		
			
				
					                          " Procedure %a specified as returning boolean, but returns nothing " 
 
			
		
	
		
			
				
					                          Typ . Procname . pp  callee_pname 
 
			
		
	
		
			
				
					                  end 
 
			
		
	
		
			
				
					              |  NoEffect  -> 
 
			
		
	
		
			
				
					                  match  get_summary  pdesc  callee_pname  actuals  loc  tenv  with 
 
			
		
	
		
			
				
					                  |  Some  ( callee_threads ,  callee_locks ,  callee_accesses ,  return_attributes )  -> 
 
			
		
	
		
			
				
					                      let  update_caller_accesses  pre  callee_accesses  caller_accesses  = 
 
			
		
	
		
			
				
					                        let  combined_accesses  = 
 
			
		
	
		
			
				
					                          PathDomain . with_callsite  callee_accesses  ( CallSite . make  callee_pname  loc ) 
 
			
		
	
		
			
				
					                          | >  PathDomain . join  ( AccessDomain . get_accesses  pre  caller_accesses )  in 
 
			
		
	
		
			
				
					                        AccessDomain . add  pre  combined_accesses  caller_accesses  in 
 
			
		
	
		
			
				
					                      let  locks  =  callee_locks  | |  astate . locks  in 
 
			
		
	
		
			
				
					                      let  threads  =  callee_threads  | |  astate . threads  in 
 
			
		
	
		
			
				
					                      let  unprotected  =  is_unprotected  locks  pdesc  in 
 
			
		
	
		
			
				
					                      (*  add [ownership_accesses] to the [accesses_acc] with a protected pre if 
 
			
		
	
		
			
				
					                         [ exp ]  is  owned ,  and  an  appropriate  unprotected  pre  otherwise  * ) 
 
			
		
	
		
			
				
					                      let  add_ownership_access  ownership_accesses  actual_exp  accesses_acc  = 
 
			
		
	
		
			
				
					                        match  actual_exp  with 
 
			
		
	
		
			
				
					                        |  HilExp . Constant  _  -> 
 
			
		
	
		
			
				
					                            (*  the actual is a constant, so it's owned in the caller.  *) 
 
			
		
	
		
			
				
					                            accesses_acc 
 
			
		
	
		
			
				
					                        |  HilExp . AccessPath  actual_access_path  -> 
 
			
		
	
		
			
				
					                            if  is_owned  actual_access_path  astate . attribute_map 
 
			
		
	
		
			
				
					                            then 
 
			
		
	
		
			
				
					                              (*  the actual passed to the current callee is owned. drop all the 
 
			
		
	
		
			
				
					                                   conditional  accesses  for  that  actual ,  since  they're  all  safe  * ) 
 
			
		
	
		
			
				
					                              accesses_acc 
 
			
		
	
		
			
				
					                            else 
 
			
		
	
		
			
				
					                              let  pre  = 
 
			
		
	
		
			
				
					                                if  unprotected 
 
			
		
	
		
			
				
					                                then 
 
			
		
	
		
			
				
					                                  let  base  =  fst  actual_access_path  in 
 
			
		
	
		
			
				
					                                  match  FormalMap . get_formal_index  base  extras  with 
 
			
		
	
		
			
				
					                                  |  Some  formal_index  -> 
 
			
		
	
		
			
				
					                                      (*  the actual passed to the current callee is rooted in a 
 
			
		
	
		
			
				
					                                           formal  * ) 
 
			
		
	
		
			
				
					                                      AccessPrecondition . Unprotected  ( Some  formal_index ) 
 
			
		
	
		
			
				
					                                  |  None  -> 
 
			
		
	
		
			
				
					                                      match 
 
			
		
	
		
			
				
					                                        AttributeMapDomain . get_conditional_ownership_index 
 
			
		
	
		
			
				
					                                          actual_access_path 
 
			
		
	
		
			
				
					                                          astate . attribute_map 
 
			
		
	
		
			
				
					                                      with 
 
			
		
	
		
			
				
					                                      |  Some  formal_index  -> 
 
			
		
	
		
			
				
					                                          (*  access path conditionally owned if [formal_index] is 
 
			
		
	
		
			
				
					                                               owned  * ) 
 
			
		
	
		
			
				
					                                          AccessPrecondition . Unprotected  ( Some  formal_index ) 
 
			
		
	
		
			
				
					                                      |  None  -> 
 
			
		
	
		
			
				
					                                          (*  access path not rooted in a formal and not 
 
			
		
	
		
			
				
					                                               conditionally  owned  * ) 
 
			
		
	
		
			
				
					                                          AccessPrecondition . unprotected 
 
			
		
	
		
			
				
					                                else 
 
			
		
	
		
			
				
					                                  (*  access protected by held lock  *) 
 
			
		
	
		
			
				
					                                  AccessPrecondition . Protected  in 
 
			
		
	
		
			
				
					                              update_caller_accesses  pre  ownership_accesses  accesses_acc 
 
			
		
	
		
			
				
					                        |  _  -> 
 
			
		
	
		
			
				
					                            (*  couldn't find access path, don't know if it's owned  *) 
 
			
		
	
		
			
				
					                            update_caller_accesses 
 
			
		
	
		
			
				
					                              AccessPrecondition . unprotected  ownership_accesses  accesses_acc  in 
 
			
		
	
		
			
				
					                      let  accesses  = 
 
			
		
	
		
			
				
					                        let  update_accesses  pre  callee_accesses  accesses_acc  =  match  pre  with 
 
			
		
	
		
			
				
					                          |  AccessPrecondition . Protected  -> 
 
			
		
	
		
			
				
					                              update_caller_accesses  pre  callee_accesses  accesses_acc 
 
			
		
	
		
			
				
					                          |  AccessPrecondition . Unprotected  None  -> 
 
			
		
	
		
			
				
					                              let  pre'  = 
 
			
		
	
		
			
				
					                                if  unprotected 
 
			
		
	
		
			
				
					                                then  pre 
 
			
		
	
		
			
				
					                                else  AccessPrecondition . Protected  in 
 
			
		
	
		
			
				
					                              update_caller_accesses  pre'  callee_accesses  accesses_acc 
 
			
		
	
		
			
				
					                          |  AccessPrecondition . Unprotected  ( Some  index )  -> 
 
			
		
	
		
			
				
					                              add_ownership_access 
 
			
		
	
		
			
				
					                                callee_accesses  ( List . nth_exn  actuals  index )  accesses_acc  in 
 
			
		
	
		
			
				
					                        AccessDomain . fold  update_accesses  callee_accesses  astate . accesses  in 
 
			
		
	
		
			
				
					    match  instr  with 
 
			
		
	
		
			
				
					    |  Call  ( Some  ret_base ,  Direct  procname ,  actuals ,  _ ,  loc ) 
 
			
		
	
		
			
				
					      when  acquires_ownership  procname  tenv  -> 
 
			
		
	
		
			
				
					        let  accesses  = 
 
			
		
	
		
			
				
					          add_reads  actuals  loc  astate . accesses  astate . locks  astate . attribute_map  proc_data  in 
 
			
		
	
		
			
				
					        let  attribute_map  = 
 
			
		
	
		
			
				
					          AttributeMapDomain . add_attribute 
 
			
		
	
		
			
				
					            ( ret_base ,  [] )  Attribute . unconditionally_owned  astate . attribute_map  in 
 
			
		
	
		
			
				
					        {  astate  with  accesses ;  attribute_map ;  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    |  Call  ( ret_opt ,  Direct  callee_pname ,  actuals ,  call_flags ,  loc )  -> 
 
			
		
	
		
			
				
					        let  accesses  = 
 
			
		
	
		
			
				
					          add_reads  actuals  loc  astate . accesses  astate . locks  astate . attribute_map  proc_data  in 
 
			
		
	
		
			
				
					        let  astate  =  {  astate  with  accesses ;  }  in 
 
			
		
	
		
			
				
					        let  astate_callee  = 
 
			
		
	
		
			
				
					          (*  assuming that modeled procedures do not have useful summaries  *) 
 
			
		
	
		
			
				
					          if  is_thread_utils_method  " assertMainThread "  callee_pname 
 
			
		
	
		
			
				
					          then 
 
			
		
	
		
			
				
					            {  astate  with  threads  =  true ;  } 
 
			
		
	
		
			
				
					          else 
 
			
		
	
		
			
				
					            match  get_lock_model  callee_pname  with 
 
			
		
	
		
			
				
					            |  Lock  -> 
 
			
		
	
		
			
				
					                {  astate  with  locks  =  true ;  } 
 
			
		
	
		
			
				
					            |  Unlock  -> 
 
			
		
	
		
			
				
					                {  astate  with  locks  =  false ;  } 
 
			
		
	
		
			
				
					            |  LockedIfTrue  -> 
 
			
		
	
		
			
				
					                begin 
 
			
		
	
		
			
				
					                  match  ret_opt  with 
 
			
		
	
		
			
				
					                  |  Some  ret_access_path  -> 
 
			
		
	
		
			
				
					                      let  attribute_map  = 
 
			
		
	
		
			
				
					                        propagate_return_attributes 
 
			
		
	
		
			
				
					                          ret_opt 
 
			
		
	
		
			
				
					                          return_attributes 
 
			
		
	
		
			
				
					                          actuals 
 
			
		
	
		
			
				
					                          astate . attribute_map 
 
			
		
	
		
			
				
					                          extras  in 
 
			
		
	
		
			
				
					                      {  astate  with  locks ;  threads ;  accesses ;  attribute_map ;  } 
 
			
		
	
		
			
				
					                        AttributeMapDomain . add_attribute 
 
			
		
	
		
			
				
					                          ( ret_access_path ,  [] ) 
 
			
		
	
		
			
				
					                          ( Choice  Choice . LockHeld ) 
 
			
		
	
		
			
				
					                          astate . attribute_map  in 
 
			
		
	
		
			
				
					                      {  astate  with  attribute_map ;  } 
 
			
		
	
		
			
				
					                  |  None  -> 
 
			
		
	
		
			
				
					                      let  should_assume_returns_ownership  ( call_flags  :  CallFlags . t )  actuals  = 
 
			
		
	
		
			
				
					                        (*  assume non-interface methods with no summary and no parameters return 
 
			
		
	
		
			
				
					                           ownership  * ) 
 
			
		
	
		
			
				
					                        not  ( call_flags . cf_interface )  &&  List . is_empty  actuals  in 
 
			
		
	
		
			
				
					                      if  is_box  callee_pname 
 
			
		
	
		
			
				
					                      then 
 
			
		
	
		
			
				
					                        match  ret_opt ,  actuals  with 
 
			
		
	
		
			
				
					                        |  Some  ret ,  HilExp . AccessPath  actual_ap  ::  _ 
 
			
		
	
		
			
				
					                          when  AttributeMapDomain . has_attribute 
 
			
		
	
		
			
				
					                              actual_ap  Functional  astate . attribute_map  -> 
 
			
		
	
		
			
				
					                            (*  TODO: check for constants, which are functional?  *) 
 
			
		
	
		
			
				
					                            let  attribute_map  = 
 
			
		
	
		
			
				
					                              AttributeMapDomain . add_attribute 
 
			
		
	
		
			
				
					                                ( ret ,  [] ) 
 
			
		
	
		
			
				
					                                Functional 
 
			
		
	
		
			
				
					                                astate . attribute_map  in 
 
			
		
	
		
			
				
					                            {  astate  with  attribute_map ;  } 
 
			
		
	
		
			
				
					                        |  _  -> 
 
			
		
	
		
			
				
					                            astate 
 
			
		
	
		
			
				
					                      else  if  should_assume_returns_ownership  call_flags  actuals 
 
			
		
	
		
			
				
					                      then 
 
			
		
	
		
			
				
					                        match  ret_opt  with 
 
			
		
	
		
			
				
					                        |  Some  ret  -> 
 
			
		
	
		
			
				
					                            let  attribute_map  = 
 
			
		
	
		
			
				
					                              AttributeMapDomain . add_attribute 
 
			
		
	
		
			
				
					                                ( ret ,  [] ) 
 
			
		
	
		
			
				
					                                Attribute . unconditionally_owned 
 
			
		
	
		
			
				
					                                astate . attribute_map  in 
 
			
		
	
		
			
				
					                            {  astate  with  attribute_map ;  } 
 
			
		
	
		
			
				
					                        |  None  -> 
 
			
		
	
		
			
				
					                            astate 
 
			
		
	
		
			
				
					                      else 
 
			
		
	
		
			
				
					                        astate  in 
 
			
		
	
		
			
				
					          begin 
 
			
		
	
		
			
				
					            match  ret_opt  with 
 
			
		
	
		
			
				
					            |  Some  ( _ ,  {  Typ . desc = Typ . Tint  ILong  |  Tfloat  FDouble  } )  -> 
 
			
		
	
		
			
				
					                (*  writes to longs and doubles are not guaranteed to be atomic in Java, so don't 
 
			
		
	
		
			
				
					                   bother  tracking  whether  a  returned  long  or  float  value  is  functional  * ) 
 
			
		
	
		
			
				
					                astate_callee 
 
			
		
	
		
			
				
					            |  Some  ret  -> 
 
			
		
	
		
			
				
					                let  add_if_annotated  predicate  attribute  attribute_map  = 
 
			
		
	
		
			
				
					                  if  PatternMatch . override_exists  predicate  tenv  callee_pname 
 
			
		
	
		
			
				
					                  then 
 
			
		
	
		
			
				
					                    AttributeMapDomain . add_attribute  ( ret ,  [] )  attribute  attribute_map 
 
			
		
	
		
			
				
					                  else 
 
			
		
	
		
			
				
					                    attribute_map  in 
 
			
		
	
		
			
				
					                let  attribute_map  = 
 
			
		
	
		
			
				
					                  add_if_annotated  is_functional  Functional  astate_callee . attribute_map 
 
			
		
	
		
			
				
					                  | >  add_if_annotated 
 
			
		
	
		
			
				
					                    ( has_return_annot  Annotations . ia_is_returns_ownership ) 
 
			
		
	
		
			
				
					                    Domain . Attribute . unconditionally_owned  in 
 
			
		
	
		
			
				
					                {  astate_callee  with  attribute_map ;  } 
 
			
		
	
		
			
				
					            |  _  -> 
 
			
		
	
		
			
				
					                astate_callee 
 
			
		
	
		
			
				
					          end 
 
			
		
	
		
			
				
					                      failwithf 
 
			
		
	
		
			
				
					                        " Procedure %a specified as returning boolean, but returns nothing " 
 
			
		
	
		
			
				
					                        Typ . Procname . pp  callee_pname 
 
			
		
	
		
			
				
					                end 
 
			
		
	
		
			
				
					            |  NoEffect  -> 
 
			
		
	
		
			
				
					                match  get_summary  pdesc  callee_pname  actuals  loc  tenv  with 
 
			
		
	
		
			
				
					                |  Some  ( callee_threads ,  callee_locks ,  callee_accesses ,  return_attributes )  -> 
 
			
		
	
		
			
				
					                    let  update_caller_accesses  pre  callee_accesses  caller_accesses  = 
 
			
		
	
		
			
				
					                      let  combined_accesses  = 
 
			
		
	
		
			
				
					                        PathDomain . with_callsite  callee_accesses  ( CallSite . make  callee_pname  loc ) 
 
			
		
	
		
			
				
					                        | >  PathDomain . join  ( AccessDomain . get_accesses  pre  caller_accesses )  in 
 
			
		
	
		
			
				
					                      AccessDomain . add  pre  combined_accesses  caller_accesses  in 
 
			
		
	
		
			
				
					                    let  locks  =  callee_locks  | |  astate . locks  in 
 
			
		
	
		
			
				
					                    let  threads  =  callee_threads  | |  astate . threads  in 
 
			
		
	
		
			
				
					                    let  unprotected  =  is_unprotected  locks  pdesc  in 
 
			
		
	
		
			
				
					                    (*  add [ownership_accesses] to the [accesses_acc] with a protected pre if 
 
			
		
	
		
			
				
					                       [ exp ]  is  owned ,  and  an  appropriate  unprotected  pre  otherwise  * ) 
 
			
		
	
		
			
				
					                    let  add_ownership_access  ownership_accesses  actual_exp  accesses_acc  = 
 
			
		
	
		
			
				
					                      match  actual_exp  with 
 
			
		
	
		
			
				
					                      |  HilExp . Constant  _  -> 
 
			
		
	
		
			
				
					                          (*  the actual is a constant, so it's owned in the caller.  *) 
 
			
		
	
		
			
				
					                          accesses_acc 
 
			
		
	
		
			
				
					                      |  HilExp . AccessPath  actual_access_path  -> 
 
			
		
	
		
			
				
					                          if  is_owned  actual_access_path  astate . attribute_map 
 
			
		
	
		
			
				
					                          then 
 
			
		
	
		
			
				
					                            (*  the actual passed to the current callee is owned. drop all the 
 
			
		
	
		
			
				
					                                 conditional  accesses  for  that  actual ,  since  they're  all  safe  * ) 
 
			
		
	
		
			
				
					                            accesses_acc 
 
			
		
	
		
			
				
					                          else 
 
			
		
	
		
			
				
					                            let  pre  = 
 
			
		
	
		
			
				
					                              if  unprotected 
 
			
		
	
		
			
				
					                              then 
 
			
		
	
		
			
				
					                                let  base  =  fst  actual_access_path  in 
 
			
		
	
		
			
				
					                                match  FormalMap . get_formal_index  base  extras  with 
 
			
		
	
		
			
				
					                                |  Some  formal_index  -> 
 
			
		
	
		
			
				
					                                    (*  the actual passed to the current callee is rooted in a 
 
			
		
	
		
			
				
					                                         formal  * ) 
 
			
		
	
		
			
				
					                                    AccessPrecondition . Unprotected  ( Some  formal_index ) 
 
			
		
	
		
			
				
					                                |  None  -> 
 
			
		
	
		
			
				
					                                    match 
 
			
		
	
		
			
				
					                                      AttributeMapDomain . get_conditional_ownership_index 
 
			
		
	
		
			
				
					                                        actual_access_path 
 
			
		
	
		
			
				
					                                        astate . attribute_map 
 
			
		
	
		
			
				
					                                    with 
 
			
		
	
		
			
				
					                                    |  Some  formal_index  -> 
 
			
		
	
		
			
				
					                                        (*  access path conditionally owned if [formal_index] is 
 
			
		
	
		
			
				
					                                             owned  * ) 
 
			
		
	
		
			
				
					                                        AccessPrecondition . Unprotected  ( Some  formal_index ) 
 
			
		
	
		
			
				
					                                    |  None  -> 
 
			
		
	
		
			
				
					                                        (*  access path not rooted in a formal and not 
 
			
		
	
		
			
				
					                                             conditionally  owned  * ) 
 
			
		
	
		
			
				
					                                        AccessPrecondition . unprotected 
 
			
		
	
		
			
				
					                              else 
 
			
		
	
		
			
				
					                                (*  access protected by held lock  *) 
 
			
		
	
		
			
				
					                                AccessPrecondition . Protected  in 
 
			
		
	
		
			
				
					                            update_caller_accesses  pre  ownership_accesses  accesses_acc 
 
			
		
	
		
			
				
					                      |  _  -> 
 
			
		
	
		
			
				
					                          (*  couldn't find access path, don't know if it's owned  *) 
 
			
		
	
		
			
				
					                          update_caller_accesses 
 
			
		
	
		
			
				
					                            AccessPrecondition . unprotected  ownership_accesses  accesses_acc  in 
 
			
		
	
		
			
				
					                    let  accesses  = 
 
			
		
	
		
			
				
					                      let  update_accesses  pre  callee_accesses  accesses_acc  =  match  pre  with 
 
			
		
	
		
			
				
					                        |  AccessPrecondition . Protected  -> 
 
			
		
	
		
			
				
					                            update_caller_accesses  pre  callee_accesses  accesses_acc 
 
			
		
	
		
			
				
					                        |  AccessPrecondition . Unprotected  None  -> 
 
			
		
	
		
			
				
					                            let  pre'  = 
 
			
		
	
		
			
				
					                              if  unprotected 
 
			
		
	
		
			
				
					                              then  pre 
 
			
		
	
		
			
				
					                              else  AccessPrecondition . Protected  in 
 
			
		
	
		
			
				
					                            update_caller_accesses  pre'  callee_accesses  accesses_acc 
 
			
		
	
		
			
				
					                        |  AccessPrecondition . Unprotected  ( Some  index )  -> 
 
			
		
	
		
			
				
					                            add_ownership_access 
 
			
		
	
		
			
				
					                              callee_accesses  ( List . nth_exn  actuals  index )  accesses_acc  in 
 
			
		
	
		
			
				
					                      AccessDomain . fold  update_accesses  callee_accesses  astate . accesses  in 
 
			
		
	
		
			
				
					                    let  attribute_map  = 
 
			
		
	
		
			
				
					                      propagate_return_attributes 
 
			
		
	
		
			
				
					                        ret_opt 
 
			
		
	
		
			
				
					                        return_attributes 
 
			
		
	
		
			
				
					                        actuals 
 
			
		
	
		
			
				
					                        astate . attribute_map 
 
			
		
	
		
			
				
					                        extras  in 
 
			
		
	
		
			
				
					                    {  locks ;  threads ;  accesses ;  attribute_map ;  } 
 
			
		
	
		
			
				
					                |  None  -> 
 
			
		
	
		
			
				
					                    let  should_assume_returns_ownership  ( call_flags  :  CallFlags . t )  actuals  = 
 
			
		
	
		
			
				
					                      (*  assume non-interface methods with no summary and no parameters return 
 
			
		
	
		
			
				
					                         ownership  * ) 
 
			
		
	
		
			
				
					                      not  ( call_flags . cf_interface )  &&  List . is_empty  actuals  in 
 
			
		
	
		
			
				
					                    if  is_box  callee_pname 
 
			
		
	
		
			
				
					                    then 
 
			
		
	
		
			
				
					                      match  ret_opt ,  actuals  with 
 
			
		
	
		
			
				
					                      |  Some  ret ,  HilExp . AccessPath  actual_ap  ::  _ 
 
			
		
	
		
			
				
					                        when  AttributeMapDomain . has_attribute 
 
			
		
	
		
			
				
					                            actual_ap  Functional  astate . attribute_map  -> 
 
			
		
	
		
			
				
					                          (*  TODO: check for constants, which are functional?  *) 
 
			
		
	
		
			
				
					                          let  attribute_map  = 
 
			
		
	
		
			
				
					                            AttributeMapDomain . add_attribute 
 
			
		
	
		
			
				
					                              ( ret ,  [] ) 
 
			
		
	
		
			
				
					                              Functional 
 
			
		
	
		
			
				
					                              astate . attribute_map  in 
 
			
		
	
		
			
				
					                          {  astate  with  attribute_map ;  } 
 
			
		
	
		
			
				
					                      |  _  -> 
 
			
		
	
		
			
				
					                          astate 
 
			
		
	
		
			
				
					                    else  if  should_assume_returns_ownership  call_flags  actuals 
 
			
		
	
		
			
				
					                    then 
 
			
		
	
		
			
				
					                      match  ret_opt  with 
 
			
		
	
		
			
				
					                      |  Some  ret  -> 
 
			
		
	
		
			
				
					                          let  attribute_map  = 
 
			
		
	
		
			
				
					                            AttributeMapDomain . add_attribute 
 
			
		
	
		
			
				
					                              ( ret ,  [] ) 
 
			
		
	
		
			
				
					                              Attribute . unconditionally_owned 
 
			
		
	
		
			
				
					                              astate . attribute_map  in 
 
			
		
	
		
			
				
					                          {  astate  with  attribute_map ;  } 
 
			
		
	
		
			
				
					                      |  None  -> 
 
			
		
	
		
			
				
					                          astate 
 
			
		
	
		
			
				
					                    else 
 
			
		
	
		
			
				
					                      astate  in 
 
			
		
	
		
			
				
					        begin 
 
			
		
	
		
			
				
					          match  ret_opt  with 
 
			
		
	
		
			
				
					          |  Some  ( _ ,  {  Typ . desc = Typ . Tint  ILong  |  Tfloat  FDouble  } )  -> 
 
			
		
	
		
			
				
					              (*  writes to longs and doubles are not guaranteed to be atomic in Java, so don't 
 
			
		
	
		
			
				
					                 bother  tracking  whether  a  returned  long  or  float  value  is  functional  * ) 
 
			
		
	
		
			
				
					              astate_callee 
 
			
		
	
		
			
				
					          |  Some  ret  -> 
 
			
		
	
		
			
				
					              let  add_if_annotated  predicate  attribute  attribute_map  = 
 
			
		
	
		
			
				
					                if  PatternMatch . override_exists  predicate  tenv  callee_pname 
 
			
		
	
		
			
				
					                then 
 
			
		
	
		
			
				
					                  AttributeMapDomain . add_attribute  ( ret ,  [] )  attribute  attribute_map 
 
			
		
	
		
			
				
					                else 
 
			
		
	
		
			
				
					                  attribute_map  in 
 
			
		
	
		
			
				
					              let  attribute_map  = 
 
			
		
	
		
			
				
					                add_if_annotated  is_functional  Functional  astate_callee . attribute_map 
 
			
		
	
		
			
				
					                | >  add_if_annotated 
 
			
		
	
		
			
				
					                  ( has_return_annot  Annotations . ia_is_returns_ownership ) 
 
			
		
	
		
			
				
					                  Domain . Attribute . unconditionally_owned  in 
 
			
		
	
		
			
				
					              {  astate_callee  with  attribute_map ;  } 
 
			
		
	
		
			
				
					          |  _  -> 
 
			
		
	
		
			
				
					              astate_callee 
 
			
		
	
		
			
				
					        end 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      |  HilInstr . Write  ( lhs_access_path ,  rhs_exp ,  loc )  -> 
 
			
		
	
		
			
				
					          let  rhs_accesses  = 
 
			
		
	
		
			
				
					    |  Write  ( lhs_access_path ,  rhs_exp ,  loc )  -> 
 
			
		
	
		
			
				
					        let  rhs_accesses  = 
 
			
		
	
		
			
				
					          add_access 
 
			
		
	
		
			
				
					            rhs_exp  loc  Read  astate . accesses  astate . locks  astate . attribute_map  proc_data  in 
 
			
		
	
		
			
				
					        let  rhs_access_paths  =  HilExp . get_access_paths  rhs_exp  in 
 
			
		
	
		
			
				
					        let  is_functional  = 
 
			
		
	
		
			
				
					          not  ( List . is_empty  rhs_access_paths )  && 
 
			
		
	
		
			
				
					          List . for_all 
 
			
		
	
		
			
				
					            ~ f : ( fun  access_path  -> 
 
			
		
	
		
			
				
					                AttributeMapDomain . has_attribute  access_path  Functional  astate . attribute_map ) 
 
			
		
	
		
			
				
					            rhs_access_paths  in 
 
			
		
	
		
			
				
					        let  accesses  = 
 
			
		
	
		
			
				
					          if  is_functional 
 
			
		
	
		
			
				
					          then 
 
			
		
	
		
			
				
					            (*  we want to forget about writes to @Functional fields altogether, otherwise we'll 
 
			
		
	
		
			
				
					               report  spurious  read / write  races  * ) 
 
			
		
	
		
			
				
					            rhs_accesses 
 
			
		
	
		
			
				
					          else 
 
			
		
	
		
			
				
					            add_access 
 
			
		
	
		
			
				
					              rhs_exp  loc  Read  astate . accesses  astate . locks  astate . attribute_map  proc_data  in 
 
			
		
	
		
			
				
					          let  rhs_access_paths  =  HilExp . get_access_paths  rhs_exp  in 
 
			
		
	
		
			
				
					          let  is_functional  = 
 
			
		
	
		
			
				
					            not  ( List . is_empty  rhs_access_paths )  && 
 
			
		
	
		
			
				
					            List . for_all 
 
			
		
	
		
			
				
					              ~ f : ( fun  access_path  -> 
 
			
		
	
		
			
				
					                  AttributeMapDomain . has_attribute  access_path  Functional  astate . attribute_map ) 
 
			
		
	
		
			
				
					              rhs_access_paths  in 
 
			
		
	
		
			
				
					          let  accesses  = 
 
			
		
	
		
			
				
					            if  is_functional 
 
			
		
	
		
			
				
					            then 
 
			
		
	
		
			
				
					              (*  we want to forget about writes to @Functional fields altogether, otherwise we'll 
 
			
		
	
		
			
				
					                 report  spurious  read / write  races  * ) 
 
			
		
	
		
			
				
					              ( AccessPath  lhs_access_path ) 
 
			
		
	
		
			
				
					              loc 
 
			
		
	
		
			
				
					              Write 
 
			
		
	
		
			
				
					              rhs_accesses 
 
			
		
	
		
			
				
					            else 
 
			
		
	
		
			
				
					              add_access 
 
			
		
	
		
			
				
					                ( AccessPath  lhs_access_path ) 
 
			
		
	
		
			
				
					                loc 
 
			
		
	
		
			
				
					                Write 
 
			
		
	
		
			
				
					                rhs_accesses 
 
			
		
	
		
			
				
					                astate . locks 
 
			
		
	
		
			
				
					                astate . attribute_map 
 
			
		
	
		
			
				
					                proc_data  in 
 
			
		
	
		
			
				
					          let  attribute_map  = 
 
			
		
	
		
			
				
					            propagate_attributes 
 
			
		
	
		
			
				
					              lhs_access_path  ( HilExp . get_access_paths  rhs_exp )  astate . attribute_map  extras  in 
 
			
		
	
		
			
				
					          {  astate  with  accesses ;  attribute_map ;  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					      |  HilInstr . Assume  ( assume_exp ,  _ ,  _ ,  loc )  -> 
 
			
		
	
		
			
				
					          let  rec  eval_binop  op  var  e1  e2  = 
 
			
		
	
		
			
				
					            match  eval_bexp  var  e1 ,  eval_bexp  var  e2  with 
 
			
		
	
		
			
				
					            |  Some  b1 ,  Some  b2  ->  Some  ( op  b1  b2 ) 
 
			
		
	
		
			
				
					            |  _  ->  None 
 
			
		
	
		
			
				
					          (*  return Some bool_value if the given boolean expression evaluates to bool_value when 
 
			
		
	
		
			
				
					             [ var ]  is  set  to  true .  return  None  if  it  has  free  variables  that  stop  us  from 
 
			
		
	
		
			
				
					             evaluating  it  * ) 
 
			
		
	
		
			
				
					          and  eval_bexp  var  =  function 
 
			
		
	
		
			
				
					            |  HilExp . AccessPath  ap  when  AccessPath . Raw . equal  ap  var  -> 
 
			
		
	
		
			
				
					                Some  true 
 
			
		
	
		
			
				
					            |  HilExp . Constant  c  -> 
 
			
		
	
		
			
				
					                Some  ( not  ( Const . iszero_int_float  c ) ) 
 
			
		
	
		
			
				
					            |  HilExp . UnaryOperator  ( Unop . LNot ,  e ,  _ )  -> 
 
			
		
	
		
			
				
					                let  b_opt  =  eval_bexp  var  e  in 
 
			
		
	
		
			
				
					                Option . map  ~ f : not  b_opt 
 
			
		
	
		
			
				
					            |  HilExp . BinaryOperator  ( Binop . LAnd ,  e1 ,  e2 )  -> 
 
			
		
	
		
			
				
					                eval_binop  ( && )  var  e1  e2 
 
			
		
	
		
			
				
					            |  HilExp . BinaryOperator  ( Binop . LOr ,  e1 ,  e2 )  -> 
 
			
		
	
		
			
				
					                eval_binop  ( | | )  var  e1  e2 
 
			
		
	
		
			
				
					            |  HilExp . BinaryOperator  ( Binop . Eq ,  e1 ,  e2 )  -> 
 
			
		
	
		
			
				
					                eval_binop  Bool . equal  var  e1  e2 
 
			
		
	
		
			
				
					            |  HilExp . BinaryOperator  ( Binop . Ne ,  e1 ,  e2 )  -> 
 
			
		
	
		
			
				
					                eval_binop  ( < > )  var  e1  e2 
 
			
		
	
		
			
				
					            |  _  -> 
 
			
		
	
		
			
				
					                (*  non-boolean expression; can't evaluate it  *) 
 
			
		
	
		
			
				
					                None  in 
 
			
		
	
		
			
				
					          let  add_choice  bool_value  acc  =  function 
 
			
		
	
		
			
				
					            |  Choice . LockHeld  -> 
 
			
		
	
		
			
				
					                let  locks  =  bool_value  in 
 
			
		
	
		
			
				
					                {  acc  with  locks ;  } 
 
			
		
	
		
			
				
					            |  Choice . OnMainThread  -> 
 
			
		
	
		
			
				
					                let  threads  =  bool_value  in 
 
			
		
	
		
			
				
					                {  acc  with  threads ;  }  in 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					          let  accesses  = 
 
			
		
	
		
			
				
					            add_access 
 
			
		
	
		
			
				
					              assume_exp  loc  Read  astate . accesses  astate . locks  astate . attribute_map  proc_data  in 
 
			
		
	
		
			
				
					          let  astate'  = 
 
			
		
	
		
			
				
					            match  HilExp . get_access_paths  assume_exp  with 
 
			
		
	
		
			
				
					            |  [ access_path ]  -> 
 
			
		
	
		
			
				
					                let  choices  =  AttributeMapDomain . get_choices  access_path  astate . attribute_map  in 
 
			
		
	
		
			
				
					                begin 
 
			
		
	
		
			
				
					                  match  eval_bexp  access_path  assume_exp  with 
 
			
		
	
		
			
				
					                  |  Some  bool_value  -> 
 
			
		
	
		
			
				
					                      (*  prune  ( prune_exp )  can only evaluate to true if the choice is [bool_value]. 
 
			
		
	
		
			
				
					                         add  the  constraint  that  the  the  choice  must  be  [ bool_value ]  to  the  state  * ) 
 
			
		
	
		
			
				
					                      List . fold  ~ f : ( add_choice  bool_value )  ~ init : astate  choices 
 
			
		
	
		
			
				
					                  |  None  -> 
 
			
		
	
		
			
				
					                      astate 
 
			
		
	
		
			
				
					                end 
 
			
		
	
		
			
				
					            |  _  -> 
 
			
		
	
		
			
				
					                astate  in 
 
			
		
	
		
			
				
					          {  astate'  with  accesses ;  } 
 
			
		
	
		
			
				
					      |  ( HilInstr . Call  ( _ ,  Indirect  _ ,  _ ,  _ ,  _ )  as  hil_instr )  -> 
 
			
		
	
		
			
				
					          failwithf  " Unexpected indirect call instruction %a "  HilInstr . pp  hil_instr  in 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    let  f_resolve_id  id  = 
 
			
		
	
		
			
				
					      try  Some  ( IdAccessPathMapDomain . find  id  astate . id_map ) 
 
			
		
	
		
			
				
					      with  Not_found  ->  None  in 
 
			
		
	
		
			
				
					    match  HilInstr . of_sil  ~ f_resolve_id  instr  with 
 
			
		
	
		
			
				
					    |  Bind  ( id ,  access_path )  -> 
 
			
		
	
		
			
				
					        let  id_map  =  IdAccessPathMapDomain . add  id  access_path  astate . id_map  in 
 
			
		
	
		
			
				
					        {  astate  with  id_map ;  } 
 
			
		
	
		
			
				
					    |  Unbind  ids  -> 
 
			
		
	
		
			
				
					        let  id_map  = 
 
			
		
	
		
			
				
					          List . fold 
 
			
		
	
		
			
				
					            ~ f : ( fun  acc  id  ->  IdAccessPathMapDomain . remove  id  acc )  ~ init : astate . id_map  ids  in 
 
			
		
	
		
			
				
					        {  astate  with  id_map ;  } 
 
			
		
	
		
			
				
					    |  Instr  hil_instr  -> 
 
			
		
	
		
			
				
					        exec_instr_  hil_instr 
 
			
		
	
		
			
				
					    |  Ignore  -> 
 
			
		
	
		
			
				
					        astate 
 
			
		
	
		
			
				
					              astate . locks 
 
			
		
	
		
			
				
					              astate . attribute_map 
 
			
		
	
		
			
				
					              proc_data  in 
 
			
		
	
		
			
				
					        let  attribute_map  = 
 
			
		
	
		
			
				
					          propagate_attributes 
 
			
		
	
		
			
				
					            lhs_access_path  ( HilExp . get_access_paths  rhs_exp )  astate . attribute_map  extras  in 
 
			
		
	
		
			
				
					        {  astate  with  accesses ;  attribute_map ;  } 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    |  Assume  ( assume_exp ,  _ ,  _ ,  loc )  -> 
 
			
		
	
		
			
				
					        let  rec  eval_binop  op  var  e1  e2  = 
 
			
		
	
		
			
				
					          match  eval_bexp  var  e1 ,  eval_bexp  var  e2  with 
 
			
		
	
		
			
				
					          |  Some  b1 ,  Some  b2  ->  Some  ( op  b1  b2 ) 
 
			
		
	
		
			
				
					          |  _  ->  None 
 
			
		
	
		
			
				
					        (*  return Some bool_value if the given boolean expression evaluates to bool_value when 
 
			
		
	
		
			
				
					           [ var ]  is  set  to  true .  return  None  if  it  has  free  variables  that  stop  us  from 
 
			
		
	
		
			
				
					           evaluating  it  * ) 
 
			
		
	
		
			
				
					        and  eval_bexp  var  =  function 
 
			
		
	
		
			
				
					          |  HilExp . AccessPath  ap  when  AccessPath . Raw . equal  ap  var  -> 
 
			
		
	
		
			
				
					              Some  true 
 
			
		
	
		
			
				
					          |  HilExp . Constant  c  -> 
 
			
		
	
		
			
				
					              Some  ( not  ( Const . iszero_int_float  c ) ) 
 
			
		
	
		
			
				
					          |  HilExp . UnaryOperator  ( Unop . LNot ,  e ,  _ )  -> 
 
			
		
	
		
			
				
					              let  b_opt  =  eval_bexp  var  e  in 
 
			
		
	
		
			
				
					              Option . map  ~ f : not  b_opt 
 
			
		
	
		
			
				
					          |  HilExp . BinaryOperator  ( Binop . LAnd ,  e1 ,  e2 )  -> 
 
			
		
	
		
			
				
					              eval_binop  ( && )  var  e1  e2 
 
			
		
	
		
			
				
					          |  HilExp . BinaryOperator  ( Binop . LOr ,  e1 ,  e2 )  -> 
 
			
		
	
		
			
				
					              eval_binop  ( | | )  var  e1  e2 
 
			
		
	
		
			
				
					          |  HilExp . BinaryOperator  ( Binop . Eq ,  e1 ,  e2 )  -> 
 
			
		
	
		
			
				
					              eval_binop  Bool . equal  var  e1  e2 
 
			
		
	
		
			
				
					          |  HilExp . BinaryOperator  ( Binop . Ne ,  e1 ,  e2 )  -> 
 
			
		
	
		
			
				
					              eval_binop  ( < > )  var  e1  e2 
 
			
		
	
		
			
				
					          |  _  -> 
 
			
		
	
		
			
				
					              (*  non-boolean expression; can't evaluate it  *) 
 
			
		
	
		
			
				
					              None  in 
 
			
		
	
		
			
				
					        let  add_choice  bool_value  acc  =  function 
 
			
		
	
		
			
				
					          |  Choice . LockHeld  -> 
 
			
		
	
		
			
				
					              let  locks  =  bool_value  in 
 
			
		
	
		
			
				
					              {  acc  with  locks ;  } 
 
			
		
	
		
			
				
					          |  Choice . OnMainThread  -> 
 
			
		
	
		
			
				
					              let  threads  =  bool_value  in 
 
			
		
	
		
			
				
					              {  acc  with  threads ;  }  in 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        let  accesses  = 
 
			
		
	
		
			
				
					          add_access 
 
			
		
	
		
			
				
					            assume_exp  loc  Read  astate . accesses  astate . locks  astate . attribute_map  proc_data  in 
 
			
		
	
		
			
				
					        let  astate'  = 
 
			
		
	
		
			
				
					          match  HilExp . get_access_paths  assume_exp  with 
 
			
		
	
		
			
				
					          |  [ access_path ]  -> 
 
			
		
	
		
			
				
					              let  choices  =  AttributeMapDomain . get_choices  access_path  astate . attribute_map  in 
 
			
		
	
		
			
				
					              begin 
 
			
		
	
		
			
				
					                match  eval_bexp  access_path  assume_exp  with 
 
			
		
	
		
			
				
					                |  Some  bool_value  -> 
 
			
		
	
		
			
				
					                    (*  prune  ( prune_exp )  can only evaluate to true if the choice is [bool_value]. 
 
			
		
	
		
			
				
					                       add  the  constraint  that  the  the  choice  must  be  [ bool_value ]  to  the  state  * ) 
 
			
		
	
		
			
				
					                    List . fold  ~ f : ( add_choice  bool_value )  ~ init : astate  choices 
 
			
		
	
		
			
				
					                |  None  -> 
 
			
		
	
		
			
				
					                    astate 
 
			
		
	
		
			
				
					              end 
 
			
		
	
		
			
				
					          |  _  -> 
 
			
		
	
		
			
				
					              astate  in 
 
			
		
	
		
			
				
					        {  astate'  with  accesses ;  } 
 
			
		
	
		
			
				
					    |  Call  ( _ ,  Indirect  _ ,  _ ,  _ ,  _ )  -> 
 
			
		
	
		
			
				
					        failwithf  " Unexpected indirect call instruction %a "  HilInstr . pp  instr 
 
			
		
	
		
			
				
					end  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					module  Analyzer  =  AbstractInterpreter . Make  ( ProcCfg . Normal )  ( TransferFunctions )  
			
		
	
		
			
				
					module  Analyzer  =  AbstractInterpreter . Make  ( ProcCfg . Normal )  ( LowerHil . Make ( TransferFunctions ) )  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					module  Interprocedural  =  AbstractInterpreter . Interprocedural  ( Summary )  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -810,12 +798,12 @@ let analyze_procedure callback =
 
			
		
	
		
			
				
					                ~ f : add_owned_formal 
 
			
		
	
		
			
				
					                owned_formals 
 
			
		
	
		
			
				
					                ~ init : ThreadSafetyDomain . empty . attribute_map  in 
 
			
		
	
		
			
				
					            {  ThreadSafetyDomain . empty  with  attribute_map ;  threads ;  } 
 
			
		
	
		
			
				
					            {  ThreadSafetyDomain . empty  with  attribute_map ;  threads ;  } ,  IdAccessPathMapDomain . empty 
 
			
		
	
		
			
				
					          else 
 
			
		
	
		
			
				
					            {  ThreadSafetyDomain . empty  with  threads ;  }  in 
 
			
		
	
		
			
				
					            {  ThreadSafetyDomain . empty  with  threads ;  } ,  IdAccessPathMapDomain . empty in 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        match  Analyzer . compute_post  proc_data  ~ initial  with 
 
			
		
	
		
			
				
					        |  Some  threads ;  locks ;  accesses ;  attribute_map ;  }  -> 
 
			
		
	
		
			
				
					        |  Some  ( { threads ;  locks ;  accesses ;  attribute_map ;  } ,  _ ) -> 
 
			
		
	
		
			
				
					            let  return_var_ap  = 
 
			
		
	
		
			
				
					              AccessPath . of_pvar 
 
			
		
	
		
			
				
					                ( Pvar . get_ret_pvar  ( Procdesc . get_proc_name  pdesc ) )