diff --git a/infer/lib/python/inferlib/analyze.py b/infer/lib/python/inferlib/analyze.py index 366d99b9a..e0562e3b9 100644 --- a/infer/lib/python/inferlib/analyze.py +++ b/infer/lib/python/inferlib/analyze.py @@ -140,7 +140,7 @@ infer_group.add_argument('--ml_buckets', help='memory leak buckets to be checked, ' 'separated by commas. The possible ' 'buckets are cf (Core Foundation), ' - 'arc, narc (No arc), cpp') + 'arc, narc (No arc), cpp, unknown_origin') infer_group.add_argument('-nt', '--notest', action='store_true', dest='notest', diff --git a/infer/src/backend/errdesc.ml b/infer/src/backend/errdesc.ml index 5f9b457f3..57ce0e8a6 100644 --- a/infer/src/backend/errdesc.ml +++ b/infer/src/backend/errdesc.ml @@ -528,14 +528,14 @@ let explain_leak tenv hpred prop alloc_att_opt bucket = | Some instr -> if !verbose then (L.d_str "explain_leak: case not matched in instr "; Sil.d_instr instr; L.d_ln()); value_str_from_pvars_vpath [] vpath in - let exn_cat = (* decide whether Exn_user or Exn_developer *) + let exn_cat, bucket = (* decide whether Exn_user or Exn_developer *) match resource_opt with | Some _ -> (* we know it has been allocated *) - Exceptions.Exn_user + Exceptions.Exn_user, bucket | None -> if leak_from_list_abstraction hpred prop && value_str != None - then Exceptions.Exn_user (* we don't know it's been allocated, but it's coming from list abstraction and we have a name *) - else Exceptions.Exn_developer in + then Exceptions.Exn_user, bucket (* we don't know it's been allocated, but it's coming from list abstraction and we have a name *) + else Exceptions.Exn_developer, Some (Mleak_buckets.ml_bucket_unknown_origin ()) in exn_cat, Localise.desc_leak value_str resource_opt res_action_opt loc bucket (** find the dexp, if any, where the given value is stored diff --git a/infer/src/backend/errlog.ml b/infer/src/backend/errlog.ml index ebe166ca0..7c5dd21e9 100644 --- a/infer/src/backend/errlog.ml +++ b/infer/src/backend/errlog.ml @@ -160,10 +160,15 @@ let log_issue _ekind err_log loc node_id_key session ltr pre_opt exn = !Config.developer_mode = false && !Config.curr_language = Config.Java && loc.Location.line = 0 in + let hide_memory_error = + match Localise.error_desc_get_bucket desc with + | Some bucket when bucket = (Mleak_buckets.ml_bucket_unknown_origin ()) -> + not (Mleak_buckets.should_raise_leak_unknown_origin ()) + | _ -> false in let log_it = visibility == Exceptions.Exn_user || (!Config.developer_mode && visibility == Exceptions.Exn_developer) in - if log_it && not hide_java_loc_zero then begin + if log_it && not hide_java_loc_zero && not hide_memory_error then begin let added = add_issue err_log (ekind, !Config.footprint, err_name, desc, severity_to_str severity) diff --git a/infer/src/backend/inferanalyze.ml b/infer/src/backend/inferanalyze.ml index bd14d9b1a..f97578d4c 100644 --- a/infer/src/backend/inferanalyze.ml +++ b/infer/src/backend/inferanalyze.ml @@ -147,7 +147,7 @@ let arg_desc = "-objcm", Arg.Set Config.objc_memory_model_on, None, "Use ObjC memory model"; "-no_progress_bar", Arg.Unit (fun () -> Config.show_progress_bar := false), None, "Do not show a progress bar"; "-ml_buckets", Arg.Set_string ml_buckets_arg, Some "ml_buckets", - "memory leak buckets to be checked, separated by commas. The possible buckets are cf (Core Foundation), arc, narc (No arc), cpp"; + "memory leak buckets to be checked, separated by commas. The possible buckets are cf (Core Foundation), arc, narc (No arc), cpp, unknown_origin"; ] in Arg2.create_options_desc false "Analysis Options" desc in let reserved_arg = diff --git a/infer/src/backend/mleak_buckets.ml b/infer/src/backend/mleak_buckets.ml index 5baa48100..0178a4249 100644 --- a/infer/src/backend/mleak_buckets.ml +++ b/infer/src/backend/mleak_buckets.ml @@ -21,6 +21,7 @@ type mleak_bucket = | MLeak_arc | MLeak_no_arc | MLeak_cpp + | MLeak_unknown let ml_buckets = ref [] @@ -30,6 +31,7 @@ let bucket_from_string bucket_s = | "arc" -> MLeak_arc | "narc" -> MLeak_no_arc | "cpp" -> MLeak_cpp + | "unknown_origin" -> MLeak_unknown | _ -> assert false let bucket_to_string bucket = @@ -38,6 +40,7 @@ let bucket_to_string bucket = | MLeak_arc -> "Arc" | MLeak_no_arc -> "No arc" | MLeak_cpp -> "Cpp" + | MLeak_unknown -> "Unknown origin" let bucket_to_message bucket = match bucket with @@ -45,6 +48,7 @@ let bucket_to_message bucket = | MLeak_arc -> "[ARC]" | MLeak_no_arc -> "[NO ARC]" | MLeak_cpp -> "[CPP]" + | MLeak_unknown -> "[UNKNOWN ORIGIN]" let mleak_bucket_compare b1 b2 = match b1, b2 with @@ -57,6 +61,9 @@ let mleak_bucket_compare b1 b2 = | MLeak_no_arc, MLeak_no_arc -> 0 | MLeak_no_arc, _ -> -1 | _, MLeak_no_arc -> 1 + | MLeak_unknown, MLeak_unknown -> 0 + | MLeak_unknown, _ -> -1 + | _, MLeak_unknown -> 1 | MLeak_cpp, MLeak_cpp -> 0 let mleak_bucket_eq b1 b2 = @@ -83,6 +90,9 @@ let contains_narc ml_buckets = let contains_cpp ml_buckets = IList.mem mleak_bucket_eq MLeak_cpp ml_buckets +let contains_unknown_origin ml_buckets = + IList.mem mleak_bucket_eq MLeak_unknown ml_buckets + let should_raise_leak_cf typ = if contains_cf !ml_buckets then Objc_models.is_core_lib_type typ @@ -98,6 +108,12 @@ let should_raise_leak_no_arc () = not (!Config.arc_mode) else false +let should_raise_leak_unknown_origin () = + contains_unknown_origin !ml_buckets + +let ml_bucket_unknown_origin () = + bucket_to_message MLeak_unknown + (* Returns whether a memory leak should be raised for a C++ object.*) (* If ml_buckets contains cpp, then check leaks from C++ objects. *) let should_raise_cpp_leak () = diff --git a/infer/src/backend/mleak_buckets.mli b/infer/src/backend/mleak_buckets.mli index 360b15cce..112b2a9e4 100644 --- a/infer/src/backend/mleak_buckets.mli +++ b/infer/src/backend/mleak_buckets.mli @@ -22,3 +22,7 @@ val should_raise_objc_leak : Sil.typ -> string option (* Returns whether a memory leak should be raised for a C++ object.*) (* If ml_buckets contains cpp, then check leaks from C++ objects. *) val should_raise_cpp_leak : unit -> string option + +val should_raise_leak_unknown_origin : unit -> bool + +val ml_bucket_unknown_origin : unit -> string