improving error message from fragment retains View checker

Reviewed By: mburman

Differential Revision: D2928721

fb-gh-sync-id: b5a10b4
shipit-source-id: b5a10b4
master
Sam Blackshear 9 years ago committed by facebook-github-bot-1
parent bf90a64fb5
commit 556b9c121d

@ -235,6 +235,26 @@ let by_call_to tags proc_name =
let by_call_to_ra tags ra = let by_call_to_ra tags ra =
"by " ^ call_to_at_line tags ra.Sil.ra_pname ra.Sil.ra_loc "by " ^ call_to_at_line tags ra.Sil.ra_pname ra.Sil.ra_loc
let rec format_typ = function
| Sil.Tptr (typ, _) when !Config.curr_language = Config.Java ->
format_typ typ
| Sil.Tstruct { Sil.struct_name = Some name } ->
Mangled.to_string name
| Sil.Tvar tname ->
Typename.name tname
| typ ->
Sil.typ_to_string typ
let format_field f =
if !Config.curr_language = Config.Java
then Ident.java_fieldname_get_field f
else Ident.fieldname_to_string f
let format_method m =
if !Config.curr_language = Config.Java
then Procname.java_get_method m
else Procname.to_string m
let mem_dyn_allocated = "memory dynamically allocated" let mem_dyn_allocated = "memory dynamically allocated"
let lock_acquired = "lock acquired" let lock_acquired = "lock acquired"
let released = "released" let released = "released"
@ -396,6 +416,20 @@ let desc_context_leak pname context_typ fieldname leak_path : error_desc =
"Context " ^ context_str ^ "may leak during method " ^ pname_str ^ ":\n" in "Context " ^ context_str ^ "may leak during method " ^ pname_str ^ ":\n" in
{ no_desc with descriptions = [preamble; leak_root; path_str] } { no_desc with descriptions = [preamble; leak_root; path_str] }
let desc_fragment_retains_view fragment_typ fieldname fld_typ pname : error_desc =
(* TODO: try advice *)
let problem =
Printf.sprintf "Fragment %s does not nullify View field %s (type %s) in %s."
(format_typ fragment_typ)
(format_field fieldname)
(format_typ fld_typ)
(format_method pname) in
let consequences =
"If this Fragment is placed on the back stack, a reference to this (probably dead) View will be retained." in
let advice =
"In general, it is a good idea to initialize View's in onCreateView, then nullify them in onDestroyView." in
{ no_desc with descriptions = [problem; consequences; advice] }
let desc_custom_error loc : error_desc = let desc_custom_error loc : error_desc =
{ no_desc with descriptions = ["detected"; at_line (Tags.create ()) loc] } { no_desc with descriptions = ["detected"; at_line (Tags.create ()) loc] }

@ -207,6 +207,9 @@ val java_unchecked_exn_desc : Procname.t -> Typename.t -> string -> error_desc
val desc_context_leak : val desc_context_leak :
Procname.t -> Sil.typ -> Ident.fieldname -> (Ident.fieldname option * Sil.typ) list -> error_desc Procname.t -> Sil.typ -> Ident.fieldname -> (Ident.fieldname option * Sil.typ) list -> error_desc
val desc_fragment_retains_view :
Sil.typ -> Ident.fieldname -> Sil.typ -> Procname.t -> error_desc
(* Create human-readable error description for assertion failures *) (* Create human-readable error description for assertion failures *)
val desc_custom_error : Location.t -> error_desc val desc_custom_error : Location.t -> error_desc

@ -12,18 +12,11 @@
module P = Printf module P = Printf
open Utils open Utils
let report_error fld fld_typ pname pdesc = let report_error fragment_typ fld fld_typ pname pdesc =
let retained_view = "CHECKERS_FRAGMENT_RETAINS_VIEW" in let retained_view = "CHECKERS_FRAGMENT_RETAINS_VIEW" in
let fld_decl_class, fld_name = let description = Localise.desc_fragment_retains_view fragment_typ fld fld_typ pname in
Ident.java_fieldname_get_class fld, Ident.java_fieldname_get_field fld in let exn = Exceptions.Checkers (retained_view, description) in
let description =
P.sprintf
"Fragment %s does not nullify View field %s (type %s) in onDestroyView. If the Fragment is placed on the back stack, a reference to the View may be retained."
fld_decl_class
fld_name
(Sil.typ_to_string (Sil.typ_strip_ptr fld_typ)) in
let loc = Cfg.Procdesc.get_loc pdesc in let loc = Cfg.Procdesc.get_loc pdesc in
let exn = Exceptions.Checkers (retained_view, Localise.verbatim_desc description) in
Reporting.log_error pname ~loc:(Some loc) exn Reporting.log_error pname ~loc:(Some loc) exn
let callback_fragment_retains_view { Callbacks.proc_desc; proc_name; tenv } = let callback_fragment_retains_view { Callbacks.proc_desc; proc_name; tenv } =
@ -54,9 +47,9 @@ let callback_fragment_retains_view { Callbacks.proc_desc; proc_name; tenv } =
let fields_nullified = PatternMatch.get_fields_nullified proc_desc in let fields_nullified = PatternMatch.get_fields_nullified proc_desc in
(* report if a field is declared by C, but not nulled out in C.onDestroyView *) (* report if a field is declared by C, but not nulled out in C.onDestroyView *)
IList.iter IList.iter
(fun (fname, typ, _) -> (fun (fname, fld_typ, _) ->
if not (Ident.FieldSet.mem fname fields_nullified) then if not (Ident.FieldSet.mem fname fields_nullified) then
report_error fname typ proc_name proc_desc) report_error typ fname fld_typ proc_name proc_desc)
declared_view_fields declared_view_fields
| _ -> () | _ -> ()
end end

Loading…
Cancel
Save