[starvation] use access expressions instead of access paths

Summary:
The goals are:
- Increase precision in C-languages by ditching access paths.
- Help with eventually sharing the abstract address module with RacerD.
- Reports are now language-mode specific (eg `->` in clang vs `.` in Java).

It's not exactly access expressions used here.  Instead the pattern `(base, access list)` is used where `access` is `HilExp.Access.t`.  This is done to ease the way `deriving` is used for creating two comparison functions, one that cares about the root variable and one that doesn't; and also because the main function that recurses over accesses (`normalise_access_list`) visits the accesses from innermost to outermost.

Also, kill some dead code.

Reviewed By: skcho

Differential Revision: D19741545

fbshipit-source-id: 013bf1a89
master
Nikos Gorogiannis 5 years ago committed by Facebook Github Bot
parent b5562f124a
commit a6da208e9d

@ -215,13 +215,6 @@ module Raw = struct
let is_prefix ap1 ap2 = chop_prefix ~prefix:ap1 ap2 |> Option.is_some let is_prefix ap1 ap2 = chop_prefix ~prefix:ap1 ap2 |> Option.is_some
let replace_prefix ~prefix access_path replace_with =
match chop_prefix ~prefix access_path with
| Some remaining_accesses ->
Some (append replace_with remaining_accesses)
| None ->
None
end end
module Abs = struct module Abs = struct
@ -281,47 +274,3 @@ module BaseMap = PrettyPrintable.MakePPMap (struct
let pp = pp_base let pp = pp_base
end) end)
(* transform an access path that starts on "this" of an inner class but which breaks out to
access outer class fields to the outermost one *)
let inner_class_normalize p =
let open Typ in
let is_synthetic_this pvar = Pvar.get_simplified_name pvar |> String.is_prefix ~prefix:"this$" in
let mk_pvar_as name pvar = Pvar.get_declaring_function pvar |> Option.map ~f:(Pvar.mk name) in
let aux = function
(* (this:InnerClass* ).(this$n:OuterClassAccessor).f. ... -> (this:OuterClass* ).f . ... *)
| Some
( ( (Var.ProgramVar pvar as root)
, ({desc= Tptr (({desc= Tstruct name} as cls), pkind)} as ptr) )
, FieldAccess first :: accesses )
when Pvar.is_this pvar && Fieldname.is_java_outer_instance first ->
Name.Java.get_outer_class name
|> Option.map ~f:(fun outer_name ->
let outer_class = mk ~default:cls (Tstruct outer_name) in
let outer_ptr = mk ~default:ptr (Tptr (outer_class, pkind)) in
((root, outer_ptr), accesses) )
(* this$n.(this$m:OuterClassAccessor).f ... -> (this$m:OuterClass* ).f . ... *)
(* happens in ctrs only *)
| Some
( (Var.ProgramVar pvar, ({desc= Tptr (({desc= Tstruct name} as cls), pkind)} as ptr))
, FieldAccess first :: accesses )
when is_synthetic_this pvar && Fieldname.is_java_outer_instance first ->
Name.Java.get_outer_class name
|> Option.bind ~f:(fun outer_name ->
let outer_class = mk ~default:cls (Tstruct outer_name) in
let outer_ptr = mk ~default:ptr (Tptr (outer_class, pkind)) in
let varname = Fieldname.get_field_name first |> Mangled.from_string in
mk_pvar_as varname pvar
|> Option.map ~f:(fun new_pvar ->
let base = base_of_pvar new_pvar outer_ptr in
(base, accesses) ) )
(* this$n.f ... -> this.f . ... *)
(* happens in ctrs only *)
| Some ((Var.ProgramVar pvar, typ), all_accesses) when is_synthetic_this pvar ->
mk_pvar_as Mangled.this pvar
|> Option.map ~f:(fun new_pvar -> (base_of_pvar new_pvar typ, all_accesses))
| _ ->
None
in
let rec loop path_opt = match aux path_opt with None -> path_opt | res -> loop res in
loop (Some p) |> Option.value ~default:p

@ -16,17 +16,14 @@ type access =
| FieldAccess of Fieldname.t (** field name *) | FieldAccess of Fieldname.t (** field name *)
[@@deriving compare, equal] [@@deriving compare, equal]
(** root var, and a list of accesses. closest to the root var is first that is, x.f.g is (** root var, and a list of accesses. closest to the root var is first that is, x.f.g is represented
representedas (x, [f; g]) *) as (x, [f; g]) *)
and t = base * access list [@@deriving compare] and t = base * access list [@@deriving compare]
val truncate : t -> t * access option val truncate : t -> t * access option
(** remove and return the last access of the access path if the access list is non-empty. returns (** remove and return the last access of the access path if the access list is non-empty. returns
the original access path * None if the access list is empty *) the original access path * None if the access list is empty *)
val get_access_type : Tenv.t -> Typ.t -> access -> Typ.t option
(** Get the type of an access, or None if the type cannot be determined *)
val get_last_access : t -> access option val get_last_access : t -> access option
(** get the last access in the list. returns None if the list is empty *) (** get the last access in the list. returns None if the list is empty *)
@ -66,18 +63,6 @@ val append : t -> access list -> t
val is_prefix : t -> t -> bool val is_prefix : t -> t -> bool
(** return true if [ap1] is a prefix of [ap2]. returns true for equal access paths *) (** return true if [ap1] is a prefix of [ap2]. returns true for equal access paths *)
val replace_prefix : prefix:t -> t -> t -> t option [@@warning "-32"]
val inner_class_normalize : t -> t
[@@warning "-32"]
(** transform an access path that starts on "this" of an inner class but which breaks out to access
outer class fields to the outermost one. Cases handled (recursively):
- (this:InnerClass* ).(this$n:OuterClassAccessor).f. ... -> (this:OuterClass* ).f . ...
- this$n.(this$m:OuterClassAccessor).f ... -> (this$m:OuterClass* ).f . ... (happens in ctrs
only)
- this$n.f ... -> this.f . ... (happens in ctrs only) *)
val equal : t -> t -> bool val equal : t -> t -> bool
val equal_base : base -> base -> bool val equal_base : base -> base -> bool
@ -88,8 +73,6 @@ val pp_base : Format.formatter -> base -> unit
val pp_access : Format.formatter -> access -> unit val pp_access : Format.formatter -> access -> unit
val pp_access_list : Format.formatter -> access list -> unit [@@warning "-32"]
module Abs : sig module Abs : sig
type raw = t type raw = t

@ -499,15 +499,6 @@ module Name = struct
let split_typename typename = Split.of_string (name typename) let split_typename typename = Split.of_string (name typename)
let get_outer_class class_name =
let {Split.package; type_name} = split_typename class_name in
match String.rsplit2 ~on:'$' type_name with
| Some (parent_class, _) ->
Some (from_package_class (Option.value ~default:"" package) parent_class)
| None ->
None
let is_anonymous_inner_class_name class_name = let is_anonymous_inner_class_name class_name =
let class_name_no_package = Split.type_name (split_typename class_name) in let class_name_no_package = Split.type_name (split_typename class_name) in
match String.rsplit2 class_name_no_package ~on:'$' with match String.rsplit2 class_name_no_package ~on:'$' with

@ -249,10 +249,6 @@ module Name : sig
val is_external : t -> bool val is_external : t -> bool
(** return true if the typename is in the .inferconfig list of external classes *) (** return true if the typename is in the .inferconfig list of external classes *)
val get_outer_class : t -> t option
(** Given an inner classname like C$Inner1$Inner2, return Some C$Inner1. If the class is not an
inner class, return None *)
val is_anonymous_inner_class_name : t -> bool val is_anonymous_inner_class_name : t -> bool
val split_typename : t -> Split.t val split_typename : t -> Split.t

@ -9,6 +9,70 @@ module F = Format
module L = Logging module L = Logging
module MF = MarkupFormatter module MF = MarkupFormatter
type access = HilExp.t option HilExp.Access.t [@@deriving compare]
let get_access_typ tenv prev_typ (access : access) =
let lookup tn = Tenv.lookup tenv tn in
match access with
| FieldAccess field_name ->
Struct.get_field_type_and_annotation ~lookup field_name prev_typ |> Option.map ~f:fst
| ArrayAccess (typ, _) ->
Some typ
| TakeAddress ->
Some (Typ.mk (Tptr (prev_typ, Pk_pointer)))
| Dereference -> (
match prev_typ with {Typ.desc= Tptr (typ, _)} -> Some typ | _ -> None )
type access_list = access list [@@deriving compare]
let equal_access_list = [%compare.equal: access_list]
let get_typ tenv ((_, base_typ), accesses) =
let f acc access = match acc with Some typ -> get_access_typ tenv typ access | None -> None in
List.fold accesses ~init:(Some base_typ) ~f
let normalise_access_list (accesses : access_list) =
let exception NormalisationFailure in
let rec normalise_access_list_inner (accesses : access_list) =
match accesses with
| [] ->
[]
| TakeAddress :: Dereference :: rest ->
normalise_access_list_inner rest
| TakeAddress :: _ :: _ ->
(* an address can only be dereferenced *)
raise NormalisationFailure
| access :: rest ->
access :: normalise_access_list_inner rest
in
try Some (normalise_access_list_inner accesses) with NormalisationFailure -> None
let pp_with_base pp_base fmt (base, accesses) =
let rec pp_rev_accesses fmt (accesses : access_list) =
match (accesses, !Language.curr_language) with
| [], _ ->
pp_base fmt base
| ArrayAccess _ :: rest, _ ->
F.fprintf fmt "%a[]" pp_rev_accesses rest
| FieldAccess field_name :: Dereference :: rest, _ ->
let op = match !Language.curr_language with Clang -> "->" | Java -> "." in
F.fprintf fmt "%a%s%a" pp_rev_accesses rest op Fieldname.pp field_name
| FieldAccess field_name :: rest, Clang ->
F.fprintf fmt "%a.%a" pp_rev_accesses rest Fieldname.pp field_name
| Dereference :: rest, Clang ->
F.fprintf fmt "*(%a)" pp_rev_accesses rest
| TakeAddress :: rest, Clang ->
F.fprintf fmt "&(%a)" pp_rev_accesses rest
| access :: rest, Java ->
L.internal_error "Asked to print %a in Java mode@" (HilExp.Access.pp (fun _ _ -> ())) access ;
pp_rev_accesses fmt rest
in
pp_rev_accesses fmt (List.rev accesses)
(** var type used only for printing, not comparisons *) (** var type used only for printing, not comparisons *)
module IgnoreVar = struct module IgnoreVar = struct
type t = Var.t type t = Var.t
@ -18,33 +82,49 @@ module IgnoreVar = struct
let equal _x _y = true let equal _x _y = true
end end
(** access path that does not ignore the type (like the original AccessPath.t) but which instead type raw_path = (Var.t * Typ.t) * access_list [@@deriving compare, equal]
ignores the root variable for comparisons. *)
type path = (IgnoreVar.t * Typ.t) * AccessPath.access list [@@deriving compare, equal] (** path-like type using [HilExp.Access] steps instead of [AccessPath.access]. It does not ignore
the root variable type (like the original [AccessPath.t]) but instead ignores the root variable
for comparisons. *)
type unrooted_path = (IgnoreVar.t * Typ.t) * access_list [@@deriving compare, equal]
type t = type t =
| Global of {path: AccessPath.t} (** [AccessPath] so as to include root var in comparison *) | Global of {path: raw_path} (** root var is included in comparison *)
| Class of {typename: Typ.Name.t} (** Java-only class object identified by typename *) | Class of {typename: Typ.Name.t} (** Java-only class object identified by typename *)
| Parameter of {index: int; path: path} | Parameter of {index: int; path: unrooted_path}
(** method parameter represented by its 0-indexed position *) (** method parameter represented by its 0-indexed position, root var is not used in comparison *)
[@@deriving compare, equal] [@@deriving compare, equal]
let get_typ tenv = let get_typ tenv =
let class_type = Typ.(mk (Tstruct Name.Java.java_lang_class)) in let class_type = Typ.(mk (Tstruct Name.Java.java_lang_class)) in
let some_ptr_to_class_type = Some Typ.(mk (Tptr (class_type, Pk_pointer))) in let some_ptr_to_class_type = Some Typ.(mk (Tptr (class_type, Pk_pointer))) in
function function
| Class _ -> | Class _ -> some_ptr_to_class_type | Global {path} | Parameter {path} -> get_typ tenv path
some_ptr_to_class_type
| Global {path} | Parameter {path} ->
AccessPath.get_typ path tenv
let rec norm_path tenv ((typ, (accesses : AccessPath.access list)) as path) = let append ~on_to:(base, accesses) (_, accesses') =
match normalise_access_list (accesses @ accesses') with
| Some accesses'' ->
Some (base, accesses'')
| None ->
None
(* Remove initial prefix of synthetic java fields giving access to outer-class fields.
This allows comparing as equal two paths generated by two different inner classes of the
same outer class. *)
let rec inner_class_normalise tenv ((typ, (accesses : access_list)) as path) =
match accesses with match accesses with
| (FieldAccess fieldname as access) :: rest when Fieldname.is_java_outer_instance fieldname -> ( | (Dereference as access) :: (FieldAccess fieldname as access') :: rest
match AccessPath.get_access_type tenv typ access with when Fieldname.is_java_outer_instance fieldname -> (
| Some typ' -> match get_access_typ tenv typ access with
norm_path tenv (typ', rest) | Some typ' -> (
match get_access_typ tenv typ' access' with
| Some typ'' ->
inner_class_normalise tenv (typ'', rest)
| None ->
path )
| None -> | None ->
path ) path )
| _ -> | _ ->
@ -55,8 +135,9 @@ let equal_across_threads tenv t1 t2 =
match (t1, t2) with match (t1, t2) with
| Parameter {path= (_, typ1), accesses1}, Parameter {path= (_, typ2), accesses2} -> | Parameter {path= (_, typ1), accesses1}, Parameter {path= (_, typ2), accesses2} ->
(* parameter position/names can be ignored across threads, if types and accesses are equal *) (* parameter position/names can be ignored across threads, if types and accesses are equal *)
let path1, path2 = (norm_path tenv (typ1, accesses1), norm_path tenv (typ2, accesses2)) in let path1 = inner_class_normalise tenv (typ1, accesses1) in
[%equal: Typ.t * AccessPath.access list] path1 path2 let path2 = inner_class_normalise tenv (typ2, accesses2) in
[%equal: Typ.t * access_list] path1 path2
| _, _ -> | _, _ ->
(* globals and class objects must be identical across threads *) (* globals and class objects must be identical across threads *)
equal t1 t2 equal t1 t2
@ -65,19 +146,30 @@ let equal_across_threads tenv t1 t2 =
let is_class_object = function Class _ -> true | _ -> false let is_class_object = function Class _ -> true | _ -> false
let rec make formal_map (hilexp : HilExp.t) = let rec make formal_map (hilexp : HilExp.t) =
match hilexp with let make_from_acc_exp acc_exp =
| AccessExpression access_exp -> ( match HilExp.AccessExpression.to_accesses acc_exp with
let path = HilExp.AccessExpression.to_access_path access_exp in | HilExp.AccessExpression.Base ((var, _) as base), accesses -> (
match fst (fst path) with match normalise_access_list accesses with
| Some accesses -> (
let path = (base, accesses) in
match var with
| Var.LogicalVar _ -> | Var.LogicalVar _ ->
(* ignore logical variables *) (* ignore logical variables *)
None None
| Var.ProgramVar pvar when Pvar.is_global pvar -> | Var.ProgramVar pvar when Pvar.is_global pvar ->
Some (Global {path}) Some (Global {path})
| Var.ProgramVar _ -> | Var.ProgramVar _ ->
FormalMap.get_formal_index (fst path) formal_map FormalMap.get_formal_index base formal_map
(* ignores non-formals *) (* ignores non-formals *)
|> Option.map ~f:(fun index -> Parameter {index; path}) ) |> Option.map ~f:(fun index -> Parameter {index; path}) )
| _ ->
None )
| _ ->
None
in
match hilexp with
| AccessExpression access_exp ->
make_from_acc_exp access_exp
| Constant (Cclass class_id) -> | Constant (Cclass class_id) ->
(* this is a synchronized(CLASSNAME.class) or class object construct *) (* this is a synchronized(CLASSNAME.class) or class object construct *)
let typename = Ident.name_to_string class_id |> Typ.Name.Java.from_string in let typename = Ident.name_to_string class_id |> Typ.Name.Java.from_string in
@ -89,9 +181,9 @@ let rec make formal_map (hilexp : HilExp.t) =
let pp fmt t = let pp fmt t =
let pp_path fmt ((var, typ), accesses) = let pp_path fmt path =
F.fprintf fmt "(%a:%a)" Var.pp var (Typ.pp_full Pp.text) typ ; let pp_base fmt (var, typ) = F.fprintf fmt "(%a:%a)" Var.pp var (Typ.pp_full Pp.text) typ in
if not (List.is_empty accesses) then F.fprintf fmt ".%a" AccessPath.pp_access_list accesses pp_with_base pp_base fmt path
in in
match t with match t with
| Global {path} -> | Global {path} ->
@ -114,6 +206,10 @@ let root_class = function
let describe fmt t = let describe fmt t =
let describe_path fmt path =
let describe_base fmt (var, _) = Var.pp fmt var in
pp_with_base describe_base fmt path
in
let describe_root fmt t = let describe_root fmt t =
root_class t |> Option.iter ~f:(F.fprintf fmt " in %a" (MF.wrap_monospaced Typ.Name.pp)) root_class t |> Option.iter ~f:(F.fprintf fmt " in %a" (MF.wrap_monospaced Typ.Name.pp))
in in
@ -122,7 +218,7 @@ let describe fmt t =
| Class {typename} -> | Class {typename} ->
MF.wrap_monospaced describe_class_object fmt typename MF.wrap_monospaced describe_class_object fmt typename
| Global {path} | Parameter {path} -> | Global {path} | Parameter {path} ->
F.fprintf fmt "%a%a" (MF.wrap_monospaced AccessPath.pp) path describe_root t F.fprintf fmt "%a%a" (MF.wrap_monospaced describe_path) path describe_root t
type subst = t option Array.t type subst = t option Array.t
@ -163,8 +259,12 @@ let apply_subst (subst : subst) t =
| Some (Class _ as t') as c -> | Some (Class _ as t') as c ->
L.internal_error "Cannot dereference class object %a in path %a@." pp t' pp t ; L.internal_error "Cannot dereference class object %a in path %a@." pp t' pp t ;
c c
| Some (Parameter param) -> | Some (Parameter param) -> (
Some (Parameter {param with path= AccessPath.append param.path (snd path)}) match append ~on_to:param.path path with
| Some (Global global) -> | Some path ->
Some (Global {path= AccessPath.append global.path (snd path)}) Some (Parameter {param with path})
| None ->
None )
| Some (Global global) -> (
match append ~on_to:global.path path with Some path -> Some (Global {path}) | None -> None )
with Invalid_argument _ -> None ) with Invalid_argument _ -> None )

@ -1,13 +1,13 @@
codetoanalyze/cpp/starvation/basics.cpp, basics::Basic::thread1_bad, 18, DEADLOCK, no_bucket, ERROR, [[Trace 1] `basics::Basic::thread1_bad`, locks `this.mutex_1` in `class basics::Basic`, locks `this.mutex_2` in `class basics::Basic`,[Trace 2] `basics::Basic::thread2_bad`, locks `this.mutex_2` in `class basics::Basic`, locks `this.mutex_1` in `class basics::Basic`] codetoanalyze/cpp/starvation/basics.cpp, basics::Basic::thread1_bad, 18, DEADLOCK, no_bucket, ERROR, [[Trace 1] `basics::Basic::thread1_bad`, locks `&(this->mutex_1)` in `class basics::Basic`, locks `&(this->mutex_2)` in `class basics::Basic`,[Trace 2] `basics::Basic::thread2_bad`, locks `&(this->mutex_2)` in `class basics::Basic`, locks `&(this->mutex_1)` in `class basics::Basic`]
codetoanalyze/cpp/starvation/basics.cpp, basics::Basic::thread2_bad, 26, DEADLOCK, no_bucket, ERROR, [[Trace 1] `basics::Basic::thread2_bad`, locks `this.mutex_2` in `class basics::Basic`, locks `this.mutex_1` in `class basics::Basic`,[Trace 2] `basics::Basic::thread1_bad`, locks `this.mutex_1` in `class basics::Basic`, locks `this.mutex_2` in `class basics::Basic`] codetoanalyze/cpp/starvation/basics.cpp, basics::Basic::thread2_bad, 26, DEADLOCK, no_bucket, ERROR, [[Trace 1] `basics::Basic::thread2_bad`, locks `&(this->mutex_2)` in `class basics::Basic`, locks `&(this->mutex_1)` in `class basics::Basic`,[Trace 2] `basics::Basic::thread1_bad`, locks `&(this->mutex_1)` in `class basics::Basic`, locks `&(this->mutex_2)` in `class basics::Basic`]
codetoanalyze/cpp/starvation/basics.cpp, basics::PathSensitive::FP_ok, 142, DEADLOCK, no_bucket, ERROR, [In method `basics::PathSensitive::FP_ok`, locks `this.mutex_` in `class basics::PathSensitive`, locks `this.mutex_` in `class basics::PathSensitive`] codetoanalyze/cpp/starvation/basics.cpp, basics::PathSensitive::FP_ok, 142, DEADLOCK, no_bucket, ERROR, [In method `basics::PathSensitive::FP_ok`, locks `&(this->mutex_)` in `class basics::PathSensitive`, locks `&(this->mutex_)` in `class basics::PathSensitive`]
codetoanalyze/cpp/starvation/basics.cpp, basics::SelfDeadlock::complicated_bad, 131, DEADLOCK, no_bucket, ERROR, [In method `basics::SelfDeadlock::complicated_bad`, locks `this.mutex_` in `class basics::SelfDeadlock`, locks `this.mutex_` in `class basics::SelfDeadlock`] codetoanalyze/cpp/starvation/basics.cpp, basics::SelfDeadlock::complicated_bad, 131, DEADLOCK, no_bucket, ERROR, [In method `basics::SelfDeadlock::complicated_bad`, locks `&(this->mutex_)` in `class basics::SelfDeadlock`, locks `&(this->mutex_)` in `class basics::SelfDeadlock`]
codetoanalyze/cpp/starvation/basics.cpp, basics::SelfDeadlock::interproc1_bad, 114, DEADLOCK, no_bucket, ERROR, [In method `basics::SelfDeadlock::interproc1_bad`, locks `this.mutex_` in `class basics::SelfDeadlock`,Method call: `basics::SelfDeadlock::interproc2_bad`, locks `this.mutex_` in `class basics::SelfDeadlock`] codetoanalyze/cpp/starvation/basics.cpp, basics::SelfDeadlock::interproc1_bad, 114, DEADLOCK, no_bucket, ERROR, [In method `basics::SelfDeadlock::interproc1_bad`, locks `&(this->mutex_)` in `class basics::SelfDeadlock`,Method call: `basics::SelfDeadlock::interproc2_bad`, locks `&(this->mutex_)` in `class basics::SelfDeadlock`]
codetoanalyze/cpp/starvation/basics.cpp, basics::SelfDeadlock::thread_bad, 105, DEADLOCK, no_bucket, ERROR, [In method `basics::SelfDeadlock::thread_bad`, locks `this.mutex_` in `class basics::SelfDeadlock`, locks `this.mutex_` in `class basics::SelfDeadlock`] codetoanalyze/cpp/starvation/basics.cpp, basics::SelfDeadlock::thread_bad, 105, DEADLOCK, no_bucket, ERROR, [In method `basics::SelfDeadlock::thread_bad`, locks `&(this->mutex_)` in `class basics::SelfDeadlock`, locks `&(this->mutex_)` in `class basics::SelfDeadlock`]
codetoanalyze/cpp/starvation/basics.cpp, basics::WithGuard::thread1_bad, 44, DEADLOCK, no_bucket, ERROR, [[Trace 1] `basics::WithGuard::thread1_bad`, locks `this.mutex_1` in `class basics::WithGuard`, locks `this.mutex_2` in `class basics::WithGuard`,[Trace 2] `basics::WithGuard::thread2_bad`, locks `this.mutex_2` in `class basics::WithGuard`, locks `this.mutex_1` in `class basics::WithGuard`] codetoanalyze/cpp/starvation/basics.cpp, basics::WithGuard::thread1_bad, 44, DEADLOCK, no_bucket, ERROR, [[Trace 1] `basics::WithGuard::thread1_bad`, locks `&(this->mutex_1)` in `class basics::WithGuard`, locks `&(this->mutex_2)` in `class basics::WithGuard`,[Trace 2] `basics::WithGuard::thread2_bad`, locks `&(this->mutex_2)` in `class basics::WithGuard`, locks `&(this->mutex_1)` in `class basics::WithGuard`]
codetoanalyze/cpp/starvation/basics.cpp, basics::WithGuard::thread2_bad, 49, DEADLOCK, no_bucket, ERROR, [[Trace 1] `basics::WithGuard::thread2_bad`, locks `this.mutex_2` in `class basics::WithGuard`, locks `this.mutex_1` in `class basics::WithGuard`,[Trace 2] `basics::WithGuard::thread1_bad`, locks `this.mutex_1` in `class basics::WithGuard`, locks `this.mutex_2` in `class basics::WithGuard`] codetoanalyze/cpp/starvation/basics.cpp, basics::WithGuard::thread2_bad, 49, DEADLOCK, no_bucket, ERROR, [[Trace 1] `basics::WithGuard::thread2_bad`, locks `&(this->mutex_2)` in `class basics::WithGuard`, locks `&(this->mutex_1)` in `class basics::WithGuard`,[Trace 2] `basics::WithGuard::thread1_bad`, locks `&(this->mutex_1)` in `class basics::WithGuard`, locks `&(this->mutex_2)` in `class basics::WithGuard`]
codetoanalyze/cpp/starvation/crossfile-1.cpp, CrossFileOne::lock_my_mutex_first_then_the_other, 12, DEADLOCK, no_bucket, ERROR, [[Trace 1] `CrossFileOne::lock_my_mutex_first_then_the_other`, locks `this._mutex` in `class CrossFileOne`,Method call: `CrossFileTwo::just_lock_my_mutex`, locks `other._mutex` in `class CrossFileTwo`,[Trace 2] `CrossFileTwo::lock_my_mutex_first_then_the_other`, locks `this._mutex` in `class CrossFileTwo`,Method call: `CrossFileOne::just_lock_my_mutex`, locks `other._mutex` in `class CrossFileOne`] codetoanalyze/cpp/starvation/crossfile-1.cpp, CrossFileOne::lock_my_mutex_first_then_the_other, 12, DEADLOCK, no_bucket, ERROR, [[Trace 1] `CrossFileOne::lock_my_mutex_first_then_the_other`, locks `&(this->_mutex)` in `class CrossFileOne`,Method call: `CrossFileTwo::just_lock_my_mutex`, locks `&(other->_mutex)` in `class CrossFileTwo`,[Trace 2] `CrossFileTwo::lock_my_mutex_first_then_the_other`, locks `&(this->_mutex)` in `class CrossFileTwo`,Method call: `CrossFileOne::just_lock_my_mutex`, locks `&(other->_mutex)` in `class CrossFileOne`]
codetoanalyze/cpp/starvation/crossfile-2.cpp, CrossFileTwo::lock_my_mutex_first_then_the_other, 12, DEADLOCK, no_bucket, ERROR, [[Trace 1] `CrossFileTwo::lock_my_mutex_first_then_the_other`, locks `this._mutex` in `class CrossFileTwo`,Method call: `CrossFileOne::just_lock_my_mutex`, locks `other._mutex` in `class CrossFileOne`,[Trace 2] `CrossFileOne::lock_my_mutex_first_then_the_other`, locks `this._mutex` in `class CrossFileOne`,Method call: `CrossFileTwo::just_lock_my_mutex`, locks `other._mutex` in `class CrossFileTwo`] codetoanalyze/cpp/starvation/crossfile-2.cpp, CrossFileTwo::lock_my_mutex_first_then_the_other, 12, DEADLOCK, no_bucket, ERROR, [[Trace 1] `CrossFileTwo::lock_my_mutex_first_then_the_other`, locks `&(this->_mutex)` in `class CrossFileTwo`,Method call: `CrossFileOne::just_lock_my_mutex`, locks `&(other->_mutex)` in `class CrossFileOne`,[Trace 2] `CrossFileOne::lock_my_mutex_first_then_the_other`, locks `&(this->_mutex)` in `class CrossFileOne`,Method call: `CrossFileTwo::just_lock_my_mutex`, locks `&(other->_mutex)` in `class CrossFileTwo`]
codetoanalyze/cpp/starvation/skip.cpp, skipped::Skip::not_skipped_bad, 19, DEADLOCK, no_bucket, ERROR, [In method `skipped::Skip::not_skipped_bad`,Method call: `skipped::Skip::private_deadlock`, locks `this.mutex_` in `class skipped::Skip`, locks `this.mutex_` in `class skipped::Skip`] codetoanalyze/cpp/starvation/skip.cpp, skipped::Skip::not_skipped_bad, 19, DEADLOCK, no_bucket, ERROR, [In method `skipped::Skip::not_skipped_bad`,Method call: `skipped::Skip::private_deadlock`, locks `&(this->mutex_)` in `class skipped::Skip`, locks `&(this->mutex_)` in `class skipped::Skip`]
codetoanalyze/cpp/starvation/skip.cpp, skipped::SkipTemplate<void>::not_skipped_bad, 44, DEADLOCK, no_bucket, ERROR, [In method `skipped::SkipTemplate<void>::not_skipped_bad`,Method call: `skipped::SkipTemplate<void>::private_deadlock`, locks `this.mutex_` in `class skipped::SkipTemplate<void>`, locks `this.mutex_` in `class skipped::SkipTemplate<void>`] codetoanalyze/cpp/starvation/skip.cpp, skipped::SkipTemplate<void>::not_skipped_bad, 44, DEADLOCK, no_bucket, ERROR, [In method `skipped::SkipTemplate<void>::not_skipped_bad`,Method call: `skipped::SkipTemplate<void>::private_deadlock`, locks `&(this->mutex_)` in `class skipped::SkipTemplate<void>`, locks `&(this->mutex_)` in `class skipped::SkipTemplate<void>`]
codetoanalyze/cpp/starvation/skip.cpp, skipped::UseTemplate::foo, 51, DEADLOCK, no_bucket, ERROR, [In method `skipped::UseTemplate::foo`,Method call: `skipped::SkipTemplate<void>::not_skipped_bad`,Method call: `skipped::SkipTemplate<void>::private_deadlock`, locks `this.x.mutex_` in `class skipped::UseTemplate`, locks `this.x.mutex_` in `class skipped::UseTemplate`] codetoanalyze/cpp/starvation/skip.cpp, skipped::UseTemplate::foo, 51, DEADLOCK, no_bucket, ERROR, [In method `skipped::UseTemplate::foo`,Method call: `skipped::SkipTemplate<void>::not_skipped_bad`,Method call: `skipped::SkipTemplate<void>::private_deadlock`, locks `&(this->x.mutex_)` in `class skipped::UseTemplate`, locks `&(this->x.mutex_)` in `class skipped::UseTemplate`]

Loading…
Cancel
Save