Add support to format reports natively

Reviewed By: jvillard

Differential Revision: D4715013

fbshipit-source-id: 8894299
master
Martino Luca 8 years ago committed by Facebook Github Bot
parent e3e0078272
commit a7b947f971

@ -31,7 +31,7 @@ DEFINE-CHECKER ASSIGN_POINTER_WARNING = {
is_assign_property() AND is_property_pointer_type()
HOLDS-IN-NODE ObjCPropertyDecl;
SET message = "Property `%decl_name%` is a pointer type marked with the `assign` attribute";
SET message = "Property %decl_name% is a pointer type marked with the `assign` attribute";
SET suggestion = "Use a different attribute like `strong` or `weak`.";
SET severity = "WARNING";
};

@ -13,6 +13,7 @@ open! IStd
(** Support for localisation *)
module F = Format
module MF = MarkupFormatter
type t = string * string [@@deriving compare] (* issue_id, human_readable *)
@ -289,7 +290,7 @@ let at_line tags loc =
let call_to tags proc_name =
let proc_name_str = Typ.Procname.to_simplified_string proc_name in
Tags.add tags Tags.call_procedure proc_name_str;
"call to " ^ proc_name_str
"call to " ^ MF.monospaced_to_string proc_name_str
let call_to_at_line tags proc_name loc =
(call_to tags proc_name) ^ " " ^ at_line_tag tags Tags.call_line loc
@ -464,51 +465,54 @@ let deref_str_uninitialized alloc_att_opt =
(** Java unchecked exceptions errors *)
let java_unchecked_exn_desc proc_name exn_name pre_str : error_desc =
{ no_desc with descriptions = [
Typ.Procname.to_string proc_name;
"can throw " ^ (Typ.Name.name exn_name);
MF.monospaced_to_string (Typ.Procname.to_string proc_name);
"can throw " ^ MF.monospaced_to_string (Typ.Name.name exn_name);
"whenever " ^ pre_str];
}
let desc_context_leak pname context_typ fieldname leak_path : error_desc =
let fld_str = Ident.fieldname_to_string fieldname in
let leak_root = " Static field " ^ fld_str ^ " |->\n " in
let leak_root = "Static field " ^ fld_str ^ " |->\n" in
let leak_path_entry_to_str acc entry =
let entry_str = match entry with
| (Some fld, _) -> Ident.fieldname_to_string fld
| (None, typ) -> Typ.to_string typ in
(* intentionally omit space; [typ_to_string] adds an extra space *)
acc ^ entry_str ^ " |->\n " in
acc ^ entry_str ^ " |->\n" in
let context_str = Typ.to_string context_typ in
let path_str =
let path_prefix =
if List.is_empty leak_path then "Leaked "
else (List.fold ~f:leak_path_entry_to_str ~init:"" leak_path) ^ " Leaked " in
else (List.fold ~f:leak_path_entry_to_str ~init:"" leak_path) ^ "Leaked " in
path_prefix ^ context_str in
let preamble =
let pname_str = match pname with
| Typ.Procname.Java pname_java ->
Printf.sprintf "%s.%s"
(Typ.Procname.java_get_class_name pname_java)
(Typ.Procname.java_get_method pname_java)
MF.monospaced_to_string
(Printf.sprintf "%s.%s"
(Typ.Procname.java_get_class_name pname_java)
(Typ.Procname.java_get_method pname_java))
| _ ->
"" 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 ^ MF.code_to_string (leak_root ^ path_str)] }
let desc_unsafe_guarded_by_access pname accessed_fld guarded_by_str loc =
let line_info = at_line (Tags.create ()) loc in
let accessed_fld_str = Ident.fieldname_to_string accessed_fld in
let annot_str = Printf.sprintf "`@GuardedBy(\"%s\")`" guarded_by_str in
let annot_str = Printf.sprintf "@GuardedBy(\"%s\")" guarded_by_str in
let syncronized_str =
MF.monospaced_to_string (Printf.sprintf "synchronized(%s)" guarded_by_str) in
let msg =
Printf.sprintf
"The field `%s` is annotated with %s, but the lock `%s` is not held during the access to the field `%s`. Consider wrapping the access in a `synchronized(%s)` block or annotating %s with %s"
accessed_fld_str
annot_str
guarded_by_str
Format.asprintf
"The field %a is annotated with %a, but the lock %a is not held during the access to the field %s. Consider wrapping the access in a %s block or annotating %s with %a"
MF.pp_monospaced accessed_fld_str
MF.pp_monospaced annot_str
MF.pp_monospaced guarded_by_str
line_info
guarded_by_str
syncronized_str
(Typ.Procname.to_string pname)
annot_str in
MF.pp_monospaced annot_str in
{ no_desc with descriptions = [msg]; }
@ -546,8 +550,8 @@ let dereference_string deref_str value_str access_opt loc =
String.concat ~sep:"" [
(match deref_str.value_pre with Some s -> s ^ " " | _ -> "");
(if is_call_access then "returned by " else "");
value_str;
(match deref_str.value_post with Some s -> " " ^ s | _ -> "")] in
MF.monospaced_to_string value_str;
(match deref_str.value_post with Some s -> " " ^ (MF.monospaced_to_string s) | _ -> "")] in
let access_desc = match access_opt with
| None ->
[]
@ -564,19 +568,22 @@ let dereference_string deref_str value_str access_opt loc =
["initialized automatically"] in
let problem_desc =
let nullable_text =
if Config.curr_language_is Config.Java
then "@Nullable"
else "__nullable" in
MF.monospaced_to_string
(if Config.curr_language_is Config.Java
then "@Nullable"
else "__nullable") in
let problem_str =
match Tags.get !tags Tags.nullable_src, Tags.get !tags Tags.weak_captured_var_src with
| Some nullable_src, _ ->
if String.equal nullable_src value_str
then "is annotated with " ^ nullable_text ^ " and is dereferenced without a null check"
else "is indirectly marked " ^ nullable_text ^ " (source: " ^ nullable_src ^ ") and is dereferenced without a null check"
else "is indirectly marked " ^ nullable_text ^
" (source: " ^ MF.monospaced_to_string nullable_src ^
") and is dereferenced without a null check"
| None, Some weak_var_str ->
if String.equal weak_var_str value_str then
"is a weak pointer captured in the block and is dereferenced without a null check"
else "is equal to the variable " ^ weak_var_str ^
else "is equal to the variable " ^ (MF.monospaced_to_string weak_var_str) ^
", a weak pointer captured in the block, and is dereferenced without a null check"
| None, None -> deref_str.problem_str in
[(problem_str ^ " " ^ at_line tags loc)] in
@ -586,7 +593,8 @@ let parameter_field_not_null_checked_desc (desc : error_desc) exp =
let parameter_not_nullable_desc var =
let var_s = Pvar.to_string var in
let param_not_null_desc =
"Parameter "^var_s^" is not checked for null, there could be a null pointer dereference:" in
"Parameter " ^ (MF.monospaced_to_string var_s) ^
" is not checked for null, there could be a null pointer dereference:" in
{ desc with descriptions = param_not_null_desc :: desc.descriptions;
tags = (Tags.parameter_not_null_checked, var_s) :: desc.tags; } in
let field_not_nullable_desc exp =
@ -597,7 +605,8 @@ let parameter_field_not_null_checked_desc (desc : error_desc) exp =
| _ -> "" in
let var_s = exp_to_string exp in
let field_not_null_desc =
"Instance variable "^var_s^" is not checked for null, there could be a null pointer dereference:" in
"Instance variable " ^ (MF.monospaced_to_string var_s) ^
" is not checked for null, there could be a null pointer dereference:" in
{ desc with descriptions = field_not_null_desc :: desc.descriptions;
tags = (Tags.field_not_null_checked, var_s) :: desc.tags; } in
match exp with
@ -627,8 +636,10 @@ let desc_allocation_mismatch alloc dealloc =
Tags.add tags tag_line (string_of_int loc.Location.line);
let by_call =
if Typ.Procname.equal primitive_pname called_pname then ""
else " by call to " ^ Typ.Procname.to_simplified_string called_pname in
"using " ^ Typ.Procname.to_simplified_string primitive_pname ^ by_call ^ " " ^ at_line (Tags.create ()) (* ignore the tag *) loc in
else " by call to " ^
(MF.monospaced_to_string (Typ.Procname.to_simplified_string called_pname)) in
"using " ^ (MF.monospaced_to_string (Typ.Procname.to_simplified_string primitive_pname)) ^
by_call ^ " " ^ at_line (Tags.create ()) (* ignore the tag *) loc in
let description = Format.sprintf
"%s %s is deallocated %s"
mem_dyn_allocated
@ -655,7 +666,7 @@ let desc_condition_always_true_false i cond_str_opt loc =
Tags.add tags Tags.value value;
let description = Format.sprintf
"Boolean condition %s is always %s %s"
(if String.equal value "" then "" else " " ^ value)
(if String.equal value "" then "" else " " ^ (MF.monospaced_to_string value))
tt_ff
(at_line tags loc) in
{ no_desc with descriptions = [description]; tags = !tags }
@ -663,18 +674,18 @@ let desc_condition_always_true_false i cond_str_opt loc =
let desc_deallocate_stack_variable var_str proc_name loc =
let tags = Tags.create () in
Tags.add tags Tags.value var_str;
let description = Format.sprintf
"Stack variable %s is freed by a %s"
var_str
let description = Format.asprintf
"Stack variable %a is freed by a %s"
MF.pp_monospaced var_str
(call_to_at_line tags proc_name loc) in
{ no_desc with descriptions = [description]; tags = !tags }
let desc_deallocate_static_memory const_str proc_name loc =
let tags = Tags.create () in
Tags.add tags Tags.value const_str;
let description = Format.sprintf
"Constant string %s is freed by a %s"
const_str
let description = Format.asprintf
"Constant string %a is freed by a %s"
MF.pp_monospaced const_str
(call_to_at_line tags proc_name loc) in
{ no_desc with descriptions = [description]; tags = !tags }
@ -685,15 +696,15 @@ let desc_class_cast_exception pname_opt typ_str1 typ_str2 exp_str_opt loc =
let in_expression = match exp_str_opt with
| Some exp_str ->
Tags.add tags Tags.value exp_str;
" in expression " ^ exp_str ^ " "
" in expression " ^ (MF.monospaced_to_string exp_str) ^ " "
| None -> " " in
let at_line' () = match pname_opt with
| Some proc_name -> "in " ^ call_to_at_line tags proc_name loc
| None -> at_line tags loc in
let description = Format.sprintf
"%s cannot be cast to %s %s %s"
typ_str1
typ_str2
let description = Format.asprintf
"%a cannot be cast to %a %s %s"
MF.pp_monospaced typ_str1
MF.pp_monospaced typ_str2
in_expression
(at_line' ()) in
{ no_desc with descriptions = [description]; tags = !tags }
@ -701,14 +712,14 @@ let desc_class_cast_exception pname_opt typ_str1 typ_str2 exp_str_opt loc =
let desc_divide_by_zero expr_str loc =
let tags = Tags.create () in
Tags.add tags Tags.value expr_str;
let description = Format.sprintf
"Expression %s could be zero %s"
expr_str
let description = Format.asprintf
"Expression %a could be zero %s"
MF.pp_monospaced expr_str
(at_line tags loc) in
{ no_desc with descriptions = [description]; tags = !tags }
let desc_empty_vector_access pname_opt object_str loc =
let vector_str = Format.sprintf "Vector %s" object_str in
let vector_str = Format.asprintf "Vector %a" MF.pp_monospaced object_str in
let desc = access_str_empty pname_opt in
let tags = desc.tags in
Tags.add tags Tags.empty_vector_access object_str;
@ -741,11 +752,11 @@ let desc_leak hpred_type_opt value_str_opt resource_opt resource_action_opt loc
| None -> "", "", ""
| Some s ->
Tags.add tags Tags.value s;
s, " to ", " on " in
MF.monospaced_to_string s, " to ", " on " in
let typ_str =
match hpred_type_opt with
| Some (Exp.Sizeof (Tstruct (TN_csu (Class _, _, _) as name), _, _)) ->
" of type " ^ Typ.Name.name name ^ " "
" of type " ^ MF.monospaced_to_string (Typ.Name.name name) ^ " "
| _ -> " " in
let desc_str =
match resource_opt with
@ -795,9 +806,9 @@ let desc_null_test_after_dereference expr_str line loc =
let tags = Tags.create () in
Tags.add tags Tags.dereferenced_line (string_of_int line);
Tags.add tags Tags.value expr_str;
let description = Format.sprintf
"Pointer %s was dereferenced at line %d and is tested for null %s"
expr_str
let description = Format.asprintf
"Pointer %a was dereferenced at line %d and is tested for null %s"
MF.pp_monospaced expr_str
line
(at_line tags loc) in
{ no_desc with descriptions = [description]; tags = !tags }
@ -823,20 +834,23 @@ let desc_retain_cycle cycle loc cycle_dotty =
let do_edge ((se, _), f, _) =
match se with
| Sil.Eexp(Exp.Lvar pvar, _) when Pvar.equal pvar Sil.block_pvar ->
str_cycle:=!str_cycle^" ("^(string_of_int !ct)^") a block capturing "^(Ident.fieldname_to_string f)^"; ";
str_cycle:=!str_cycle^" ("^(string_of_int !ct)^") a block capturing " ^
MF.monospaced_to_string (Ident.fieldname_to_string f)^"; ";
ct:=!ct +1;
| Sil.Eexp(Exp.Lvar pvar as e, _) ->
let e_str = Exp.to_string e in
let e_str = if Pvar.is_seed pvar then
remove_old e_str
else e_str in
str_cycle:=!str_cycle^" ("^(string_of_int !ct)^") object "^e_str^" retaining "^e_str^"."^(Ident.fieldname_to_string f)^", ";
str_cycle:=!str_cycle^" ("^(string_of_int !ct)^") object "^e_str^" retaining " ^
MF.monospaced_to_string (e_str^"."^(Ident.fieldname_to_string f))^", ";
ct:=!ct +1
| Sil.Eexp (Exp.Sizeof (typ, _, _), _) ->
let step =
" (" ^ (string_of_int !ct) ^ ") an object of "
^ (Typ.to_string typ) ^ " retaining another object via instance variable "
^ (Ident.fieldname_to_string f) ^ ", " in
" (" ^ (string_of_int !ct) ^ ") an object of " ^
MF.monospaced_to_string (Typ.to_string typ) ^
" retaining another object via instance variable " ^
MF.monospaced_to_string (Ident.fieldname_to_string f) ^ ", " in
str_cycle := !str_cycle ^ step;
ct:=!ct +1
| _ -> () in
@ -850,7 +864,7 @@ let registered_observer_being_deallocated_str obj_str =
let desc_registered_observer_being_deallocated pvar loc =
let tags = Tags.create () in
let obj_str = Pvar.to_string pvar in
let obj_str = MF.monospaced_to_string (Pvar.to_string pvar) in
{ no_desc with descriptions = [ registered_observer_being_deallocated_str obj_str ^ at_line tags loc ^
". Being still registered as observer of the notification " ^
"center, the deallocated object "
@ -871,9 +885,9 @@ let desc_unary_minus_applied_to_unsigned_expression expr_str_opt typ_str loc =
Tags.add tags Tags.value s;
"expression " ^ s
| None -> "an expression" in
let description = Format.sprintf
"A unary minus is applied to %s of type %s %s"
expression
let description = Format.asprintf
"A unary minus is applied to %a of type %s %s"
MF.pp_monospaced expression
typ_str
(at_line tags loc) in
{ no_desc with descriptions = [description]; tags = !tags }
@ -888,7 +902,7 @@ let desc_inherently_dangerous_function proc_name =
let proc_name_str = Typ.Procname.to_string proc_name in
let tags = Tags.create () in
Tags.add tags Tags.value proc_name_str;
{ no_desc with descriptions = [proc_name_str]; tags = !tags }
{ no_desc with descriptions = [MF.monospaced_to_string proc_name_str]; tags = !tags }
let desc_stack_variable_address_escape expr_str addr_dexp_str loc =
let tags = Tags.create () in
@ -898,9 +912,9 @@ let desc_stack_variable_address_escape expr_str addr_dexp_str loc =
Tags.add tags Tags.escape_to s;
"to " ^ s ^ " "
| None -> "" in
let description = Format.sprintf
"Address of stack variable %s escapes %s%s"
expr_str
let description = Format.asprintf
"Address of stack variable %a escapes %s%s"
MF.pp_monospaced expr_str
escape_to_str
(at_line tags loc) in
{ no_desc with descriptions = [description]; tags = !tags }
@ -912,37 +926,37 @@ let desc_tainted_value_reaching_sensitive_function
let description =
match taint_kind with
| PredSymb.Tk_unverified_SSL_socket ->
F.sprintf
"The hostname of SSL socket `%s` (returned from %s) has not been verified! Reading from the socket via the call to %s %s is dangerous. You should verify the hostname of the socket using a HostnameVerifier before reading; otherwise, you may be vulnerable to a man-in-the-middle attack."
expr_str
F.asprintf
"The hostname of SSL socket %a (returned from %s) has not been verified! Reading from the socket via the call to %s %s is dangerous. You should verify the hostname of the socket using a HostnameVerifier before reading; otherwise, you may be vulnerable to a man-in-the-middle attack."
MF.pp_monospaced expr_str
(format_method tainting_fun)
(format_method sensitive_fun)
(at_line tags loc)
| PredSymb.Tk_shared_preferences_data ->
F.sprintf
"`%s` holds sensitive data read from a SharedPreferences object (via call to %s). This data may leak via the call to %s %s."
expr_str
F.asprintf
"%a holds sensitive data read from a SharedPreferences object (via call to %s). This data may leak via the call to %s %s."
MF.pp_monospaced expr_str
(format_method tainting_fun)
(format_method sensitive_fun)
(at_line tags loc)
| PredSymb.Tk_privacy_annotation ->
F.sprintf
"`%s` holds privacy-sensitive data (source: call to %s). This data may leak via the call to %s %s."
expr_str
F.asprintf
"%a holds privacy-sensitive data (source: call to %s). This data may leak via the call to %s %s."
MF.pp_monospaced expr_str
(format_method tainting_fun)
(format_method sensitive_fun)
(at_line tags loc)
| PredSymb.Tk_integrity_annotation ->
F.sprintf
"`%s` holds untrusted user-controlled data (source: call to %s). This data may flow into a security-sensitive sink via the call to %s %s."
expr_str
F.asprintf
"%a holds untrusted user-controlled data (source: call to %s). This data may flow into a security-sensitive sink via the call to %s %s."
MF.pp_monospaced expr_str
(format_method tainting_fun)
(format_method sensitive_fun)
(at_line tags loc)
| PredSymb.Tk_unknown ->
F.sprintf
"Value `%s` could be insecure (tainted) due to call to function %s %s %s %s. Function %s %s"
expr_str
F.asprintf
"Value %a could be insecure (tainted) due to call to function %s %s %s %s. Function %s %s"
MF.pp_monospaced expr_str
(format_method tainting_fun)
"and is reaching sensitive function"
(format_method sensitive_fun)
@ -958,10 +972,10 @@ let desc_uninitialized_dangling_pointer_deref deref expr_str loc =
| Some s -> s
| _ -> "" in
let description =
Format.sprintf
"%s %s %s %s"
Format.asprintf
"%s %a %s %s"
prefix
expr_str
MF.pp_monospaced expr_str
deref.problem_str
(at_line tags loc) in
{ no_desc with descriptions = [description]; tags = !tags }

@ -1178,6 +1178,16 @@ and report_custom_error =
CLOpt.mk_bool ~long:"report-custom-error"
""
and report_formatter =
CLOpt.mk_symbol ~long:"report-formatter"
~parse_mode:CLOpt.(Infer [Driver; Print])
~default:`Phabricator_formatter
~symbols:[
("none", `No_formatter);
("phabricator", `Phabricator_formatter);
] ~eq:PVariant.(=)
"Which formatter to use when emitting the report"
and report_hook =
CLOpt.mk_string_opt ~long:"report-hook"
~default:(lib_dir ^/ "python" ^/ "report.py")
@ -1669,6 +1679,7 @@ and reactive_capture = !reactive_capture
and report = !report
and report_current = !report_current
and report_custom_error = !report_custom_error
and report_formatter = !report_formatter
and report_hook = !report_hook
and report_previous = !report_previous
and report_runtime_exceptions = !tracing

@ -297,6 +297,7 @@ val reactive_mode : bool
val reactive_capture : bool
val report : string option
val report_current : string option
val report_formatter : [`No_formatter | `Phabricator_formatter]
val report_hook : string option
val report_previous : string option
val report_runtime_exceptions : bool

@ -0,0 +1,68 @@
(*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
open! IStd
type 'a formatter = {
wrap_monospaced : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a -> unit;
pp_monospaced : Format.formatter -> string -> unit;
monospaced_to_string : string -> string;
wrap_code : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a -> unit;
pp_code : Format.formatter -> string -> unit;
code_to_string : string -> string;
}
module NoFormatter : sig
val formatter : 'a formatter
end = struct
let wrap_simple pp fmt x = pp fmt x
let pp_simple = wrap_simple Format.pp_print_string
let formatter = {
wrap_monospaced = wrap_simple;
pp_monospaced = pp_simple;
monospaced_to_string = Fn.id;
wrap_code = wrap_simple;
pp_code = pp_simple;
code_to_string = Fn.id
}
end
module PhabricatorFormatter : sig
val formatter : 'a formatter
end = struct
(* https://secure.phabricator.com/book/phabricator/article/remarkup/ *)
let wrap_monospaced pp fmt x = Format.fprintf fmt "`%a`" pp x
let pp_monospaced fmt s = wrap_monospaced Format.pp_print_string fmt s
let monospaced_to_string s = Format.asprintf "%a" pp_monospaced s
let wrap_code pp fmt x = Format.fprintf fmt "```%a```" pp x
let pp_code fmt s = wrap_code Format.pp_print_string fmt s
let code_to_string s = Format.asprintf "%a" pp_code s
let formatter = {
wrap_monospaced;
pp_monospaced;
monospaced_to_string;
wrap_code;
pp_code;
code_to_string;
}
end
let formatter = match Config.report_formatter with
| `No_formatter -> NoFormatter.formatter
| `Phabricator_formatter -> PhabricatorFormatter.formatter
let wrap_monospaced = formatter.wrap_monospaced
let pp_monospaced = formatter.pp_monospaced
let monospaced_to_string = formatter.monospaced_to_string
let wrap_code = formatter.wrap_code
let pp_code = formatter.pp_code
let code_to_string = formatter.code_to_string

@ -0,0 +1,26 @@
(*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
(** used to combine pp together, wrap content into a monospaced block *)
val wrap_monospaced : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a -> unit
(** pp to wrap into a monospaced block *)
val pp_monospaced : Format.formatter -> string -> unit
(* wrap into a monospaced block *)
val monospaced_to_string : string -> string
(** used to combine pp together, wrap content into a code block *)
val wrap_code : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a -> unit
(** pp to wrap into a code block *)
val pp_code : Format.formatter -> string -> unit
(* wrap into a code block *)
val code_to_string : string -> string

@ -15,6 +15,7 @@ open AbsLoc
module F = Format
module L = Logging
module MF = MarkupFormatter
module Condition =
struct
@ -129,8 +130,7 @@ let to_string : t -> string
^ (match c.trace with
Inter (_, pname, _) ->
" by call "
^ Typ.Procname.to_string pname
^ "() "
^ MF.monospaced_to_string (Typ.Procname.to_string pname ^ "()") ^ " "
| Intra _ -> "")
let subst : t -> Itv.Bound.t Itv.SubstMap.t -> Typ.Procname.t -> Typ.Procname.t -> Location.t -> t

@ -11,7 +11,7 @@ open! IStd
module F = Format
module L = Logging
module MF = MarkupFormatter
module Summary = Summary.Make (struct
type summary = ThreadSafetyDomain.summary
@ -944,7 +944,10 @@ let calculate_addendum_message tenv pname =
| Some (current_class,thread_safe_annotated_classes) ->
if not (List.mem ~equal:Typ.Name.equal thread_safe_annotated_classes current_class) then
match thread_safe_annotated_classes with
| hd::_ -> F.asprintf "\n Note: Superclass %a is marked @ThreadSafe." Typ.Name.pp hd
| hd::_ ->
F.asprintf "\n Note: Superclass %a is marked %a."
(MF.wrap_monospaced Typ.Name.pp) hd
MF.pp_monospaced "@ThreadSafe"
| [] -> ""
else ""
| _ -> ""
@ -1126,10 +1129,10 @@ let make_unprotected_write_description
tenv pname final_sink_site initial_sink_site final_sink _ _ =
Format.asprintf
"Unprotected write. Public method %a%s %s %a outside of synchronization.%s"
Typ.Procname.pp pname
(MF.wrap_monospaced Typ.Procname.pp) pname
(if CallSite.equal final_sink_site initial_sink_site then "" else " indirectly")
(if is_container_write_sink final_sink then "mutates" else "writes to field")
(pp_accesses_sink ~is_write_access:true) final_sink
(MF.wrap_monospaced (pp_accesses_sink ~is_write_access:true)) final_sink
(calculate_addendum_message tenv pname)
let make_read_write_race_description
@ -1146,11 +1149,11 @@ let make_read_write_race_description
let conflicts_description =
Format.asprintf "Potentially races with writes in method%s %a."
(if List.length conflicting_proc_names > 1 then "s" else "")
pp_proc_name_list conflicting_proc_names in
(MF.wrap_monospaced pp_proc_name_list) conflicting_proc_names in
Format.asprintf "Read/Write race. Public method %a%s reads from field %a. %s %s"
Typ.Procname.pp pname
(MF.wrap_monospaced Typ.Procname.pp) pname
(if CallSite.equal final_sink_site initial_sink_site then "" else " indirectly")
(pp_accesses_sink ~is_write_access:false) final_sink
(MF.wrap_monospaced (pp_accesses_sink ~is_write_access:false)) final_sink
conflicts_description
(calculate_addendum_message tenv pname)

@ -11,6 +11,7 @@ open! IStd
module F = Format
module L = Logging
module MF = MarkupFormatter
module CallSiteSet = AbstractDomain.FiniteSet (CallSite.Set)
module CallsDomain = AbstractDomain.Map (Annot.Map) (CallSiteSet)
@ -178,13 +179,12 @@ let report_allocation_stack
let final_trace = List.rev (update_trace call_loc trace) in
let constr_str = string_of_pname constructor_pname in
let description =
Printf.sprintf
"Method `%s` annotated with `@%s` allocates `%s` via `%s%s`"
(Typ.Procname.to_simplified_string pname)
src_annot
constr_str
stack_str
("new "^constr_str) in
Format.asprintf
"Method %a annotated with %a allocates %a via %a"
MF.pp_monospaced (Typ.Procname.to_simplified_string pname)
MF.pp_monospaced ("@" ^ src_annot)
MF.pp_monospaced constr_str
MF.pp_monospaced (stack_str ^ ("new "^constr_str)) in
let exn =
Exceptions.Checkers (allocates_memory, Localise.verbatim_desc description) in
Reporting.log_error pname ~loc:fst_call_loc ~ltr:final_trace exn
@ -196,14 +196,13 @@ let report_annotation_stack src_annot snk_annot src_pname loc trace stack_str sn
let final_trace = List.rev (update_trace call_loc trace) in
let exp_pname_str = string_of_pname snk_pname in
let description =
Printf.sprintf
"Method `%s` annotated with `@%s` calls `%s%s` where `%s` is annotated with `@%s`"
(Typ.Procname.to_simplified_string src_pname)
src_annot
stack_str
exp_pname_str
exp_pname_str
snk_annot in
Format.asprintf
"Method %a annotated with %a calls %a where %a is annotated with %a"
MF.pp_monospaced (Typ.Procname.to_simplified_string src_pname)
MF.pp_monospaced ("@" ^ src_annot)
MF.pp_monospaced (stack_str ^ exp_pname_str)
MF.pp_monospaced exp_pname_str
MF.pp_monospaced ("@" ^ snk_annot) in
let msg =
if String.equal src_annot Annotations.performance_critical
then calls_expensive_method
@ -355,11 +354,11 @@ module Interprocedural = struct
let check_expensive_subtyping_rules overridden_pname =
if not (method_is_expensive tenv overridden_pname) then
let description =
Printf.sprintf
"Method `%s` overrides unannotated method `%s` and cannot be annotated with `@%s`"
(Typ.Procname.to_string proc_name)
(Typ.Procname.to_string overridden_pname)
Annotations.expensive in
Format.asprintf
"Method %a overrides unannotated method %a and cannot be annotated with %a"
MF.pp_monospaced (Typ.Procname.to_string proc_name)
MF.pp_monospaced (Typ.Procname.to_string overridden_pname)
MF.pp_monospaced ("@" ^ Annotations.expensive) in
let exn =
Exceptions.Checkers
(expensive_overrides_unexpensive, Localise.verbatim_desc description) in

@ -10,6 +10,8 @@
open! IStd
open! PVariant
module MF = MarkupFormatter
let get_source_range an =
match an with
| Ctl_parser_types.Decl decl ->
@ -119,8 +121,9 @@ let mutable_local_vars_advice context an =
CIssue.name = "MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE";
severity = Exceptions.Kadvice;
mode = CIssue.On;
description = "Local variable '" ^ named_decl_info.ni_name
^ "' should be const to avoid reassignment";
description =
"Local variable " ^ MF.monospaced_to_string named_decl_info.ni_name ^
" should be const to avoid reassignment";
suggestion = Some "Add a const (after the asterisk for pointer types).";
loc = CFrontend_checkers.location_from_dinfo context decl_info
}

@ -9,6 +9,8 @@
open! IStd
module MF = MarkupFormatter
type linter = {
condition : CTL.t;
issue_desc : CIssue.issue_desc;
@ -47,15 +49,15 @@ let parsed_linters = ref []
let evaluate_place_holder ph an =
match ph with
| "%ivar_name%" -> CFrontend_checkers.ivar_name an
| "%decl_name%" -> CFrontend_checkers.decl_name an
| "%ivar_name%" -> MF.monospaced_to_string (CFrontend_checkers.ivar_name an)
| "%decl_name%" -> MF.monospaced_to_string (CFrontend_checkers.decl_name an)
| "%cxx_ref_captured_in_block%" ->
CFrontend_checkers.cxx_ref_captured_in_block an
MF.monospaced_to_string (CFrontend_checkers.cxx_ref_captured_in_block an)
| "%decl_ref_or_selector_name%" ->
CFrontend_checkers.decl_ref_or_selector_name an
MF.monospaced_to_string (CFrontend_checkers.decl_ref_or_selector_name an)
| "%iphoneos_target_sdk_version%" ->
CFrontend_checkers.iphoneos_target_sdk_version an
| "%available_ios_sdk%" -> CFrontend_checkers.available_ios_sdk an
MF.monospaced_to_string (CFrontend_checkers.iphoneos_target_sdk_version an)
| "%available_ios_sdk%" -> MF.monospaced_to_string (CFrontend_checkers.available_ios_sdk an)
| _ -> (Logging.err "ERROR: helper function %s is unknown. Stop.\n" ph;
assert false)

@ -11,6 +11,7 @@ open! IStd
module Hashtbl = Caml.Hashtbl
module L = Logging
module MF = MarkupFormatter
module P = Printf
(** Module for Type Error messages. *)
@ -262,7 +263,9 @@ let report_error_now tenv
"The condition %s is always %b according to the existing annotations."
(Option.value s_opt ~default:"")
b,
Some "Consider adding a `@Nullable` annotation or removing the redundant check.",
Some ("Consider adding a " ^
MF.monospaced_to_string "@Nullable" ^
" annotation or removing the redundant check."),
None,
None
| Field_not_initialized (fn, pn) ->
@ -272,24 +275,26 @@ let report_error_now tenv
else
match pn with
| Typ.Procname.Java pn_java ->
Typ.Procname.java_get_method pn_java
MF.monospaced_to_string (Typ.Procname.java_get_method pn_java)
| _ ->
Typ.Procname.to_simplified_string pn in
MF.monospaced_to_string (Typ.Procname.to_simplified_string pn) in
true,
Localise.eradicate_field_not_initialized,
P.sprintf
"Field `%s` is not initialized in %s and is not declared `@Nullable`"
(Ident.fieldname_to_simplified_string fn)
constructor_name,
Format.asprintf
"Field %a is not initialized in %s and is not declared %a"
MF.pp_monospaced (Ident.fieldname_to_simplified_string fn)
constructor_name
MF.pp_monospaced "@Nullable",
None,
Some fn,
None
| Field_not_mutable (fn, (origin_description, origin_loc, _)) ->
true,
Localise.eradicate_field_not_mutable,
P.sprintf
"Field `%s` is modified but is not declared `@Mutable`. %s"
(Ident.fieldname_to_simplified_string fn)
Format.asprintf
"Field %a is modified but is not declared %a. %s"
MF.pp_monospaced (Ident.fieldname_to_simplified_string fn)
MF.pp_monospaced "@Mutable"
origin_description,
None,
None,
@ -298,15 +303,17 @@ let report_error_now tenv
let kind_s, description = match ann with
| AnnotatedSignature.Nullable ->
Localise.eradicate_field_not_nullable,
P.sprintf
"Field `%s` can be null but is not declared `@Nullable`. %s"
(Ident.fieldname_to_simplified_string fn)
Format.asprintf
"Field %a can be null but is not declared %a. %s"
MF.pp_monospaced (Ident.fieldname_to_simplified_string fn)
MF.pp_monospaced "@Nullable"
origin_description
| AnnotatedSignature.Present ->
Localise.eradicate_field_value_absent,
P.sprintf
"Field `%s` is assigned a possibly absent value but is declared `@Present`. %s"
(Ident.fieldname_to_simplified_string fn)
Format.asprintf
"Field %a is assigned a possibly absent value but is declared %a. %s"
MF.pp_monospaced (Ident.fieldname_to_simplified_string fn)
MF.pp_monospaced "@Present"
origin_description in
true,
kind_s,
@ -326,10 +333,11 @@ let report_error_now tenv
Typ.Procname.to_simplified_string pn in
true,
Localise.eradicate_field_over_annotated,
P.sprintf
"Field `%s` is always initialized in %s but is declared `@Nullable`"
(Ident.fieldname_to_simplified_string fn)
constructor_name,
Format.asprintf
"Field %a is always initialized in %s but is declared %a"
MF.pp_monospaced (Ident.fieldname_to_simplified_string fn)
constructor_name
MF.pp_monospaced "@Nullable",
None,
Some fn,
None
@ -337,11 +345,11 @@ let report_error_now tenv
let at_index = if indexed then "element at index" else "field" in
true,
Localise.eradicate_null_field_access,
P.sprintf
"Object `%s` could be null when accessing %s `%s`. %s"
(Option.value s_opt ~default:"")
Format.asprintf
"Object %a could be null when accessing %s %a. %s"
MF.pp_monospaced (Option.value s_opt ~default:"")
at_index
(Ident.fieldname_to_simplified_string fn)
MF.pp_monospaced (Ident.fieldname_to_simplified_string fn)
origin_description,
None,
None,
@ -350,17 +358,18 @@ let report_error_now tenv
let kind_s, description = match ann with
| AnnotatedSignature.Nullable ->
Localise.eradicate_null_method_call,
P.sprintf
"The value of `%s` in the call to `%s` could be null. %s"
(Option.value s_opt ~default:"")
(Typ.Procname.to_simplified_string pn)
Format.asprintf
"The value of %a in the call to %a could be null. %s"
MF.pp_monospaced (Option.value s_opt ~default:"")
MF.pp_monospaced (Typ.Procname.to_simplified_string pn)
origin_description
| AnnotatedSignature.Present ->
Localise.eradicate_value_not_present,
P.sprintf
"The value of `%s` in the call to `%s` is not @Present. %s"
(Option.value s_opt ~default:"")
(Typ.Procname.to_simplified_string pn)
Format.asprintf
"The value of %a in the call to %a is not %a. %s"
MF.pp_monospaced (Option.value s_opt ~default:"")
MF.pp_monospaced (Typ.Procname.to_simplified_string pn)
MF.pp_monospaced "@Present"
origin_description in
true,
kind_s,
@ -372,19 +381,19 @@ let report_error_now tenv
let kind_s, description = match ann with
| AnnotatedSignature.Nullable ->
Localise.eradicate_parameter_not_nullable,
P.sprintf
"`%s` needs a non-null value in parameter %d but argument `%s` can be null. %s"
(Typ.Procname.to_simplified_string pn)
Format.asprintf
"%a needs a non-null value in parameter %d but argument %a can be null. %s"
MF.pp_monospaced (Typ.Procname.to_simplified_string pn)
n
s
MF.pp_monospaced s
origin_desc
| AnnotatedSignature.Present ->
Localise.eradicate_parameter_value_absent,
P.sprintf
"`%s` needs a present value in parameter %d but argument `%s` can be absent. %s"
(Typ.Procname.to_simplified_string pn)
Format.asprintf
"%a needs a present value in parameter %d but argument %a can be absent. %s"
MF.pp_monospaced (Typ.Procname.to_simplified_string pn)
n
s
MF.pp_monospaced s
origin_desc in
true,
kind_s,
@ -396,15 +405,17 @@ let report_error_now tenv
let kind_s, description = match ann with
| AnnotatedSignature.Nullable ->
Localise.eradicate_return_not_nullable,
P.sprintf
"Method `%s` may return null but it is not annotated with `@Nullable`. %s"
(Typ.Procname.to_simplified_string pn)
Format.asprintf
"Method %a may return null but it is not annotated with %a. %s"
MF.pp_monospaced (Typ.Procname.to_simplified_string pn)
MF.pp_monospaced "@Nullable"
origin_description
| AnnotatedSignature.Present ->
Localise.eradicate_return_value_not_present,
P.sprintf
"Method `%s` may return an absent value but it is annotated with `@Present`. %s"
(Typ.Procname.to_simplified_string pn)
Format.asprintf
"Method %a may return an absent value but it is annotated with %a. %s"
MF.pp_monospaced (Typ.Procname.to_simplified_string pn)
MF.pp_monospaced "@Present"
origin_description in
true,
kind_s,
@ -415,19 +426,21 @@ let report_error_now tenv
| Return_over_annotated pn ->
false,
Localise.eradicate_return_over_annotated,
P.sprintf
"Method `%s` is annotated with `@Nullable` but never returns null."
(Typ.Procname.to_simplified_string pn),
Format.asprintf
"Method %a is annotated with %a but never returns null."
MF.pp_monospaced (Typ.Procname.to_simplified_string pn)
MF.pp_monospaced "@Nullable",
None,
None,
None
| Inconsistent_subclass_return_annotation (pn, opn) ->
false,
Localise.eradicate_inconsistent_subclass_return_annotation,
P.sprintf
"Method `%s` is annotated with `@Nullable` but overrides unannotated method `%s`."
(Typ.Procname.to_simplified_string ~withclass: true pn)
(Typ.Procname.to_simplified_string ~withclass: true opn),
Format.asprintf
"Method %a is annotated with %a but overrides unannotated method %a."
MF.pp_monospaced (Typ.Procname.to_simplified_string ~withclass: true pn)
MF.pp_monospaced "@Nullable"
MF.pp_monospaced (Typ.Procname.to_simplified_string ~withclass: true opn),
None,
None,
None
@ -439,12 +452,15 @@ let report_error_now tenv
| n -> (string_of_int n)^"th" in
false,
Localise.eradicate_inconsistent_subclass_parameter_annotation,
P.sprintf
"%s parameter `%s` of method `%s` is not `@Nullable` but is declared `@Nullable`\
in the parent class method `%s`."
(translate_position pos) param_name
(Typ.Procname.to_simplified_string ~withclass: true pn)
(Typ.Procname.to_simplified_string ~withclass: true opn),
Format.asprintf
"%s parameter %a of method %a is not %a but is declared %a\
in the parent class method %a."
(translate_position pos)
MF.pp_monospaced param_name
MF.pp_monospaced (Typ.Procname.to_simplified_string ~withclass: true pn)
MF.pp_monospaced "@Nullable"
MF.pp_monospaced "@Nullable"
MF.pp_monospaced (Typ.Procname.to_simplified_string ~withclass: true opn),
None,
None,
None in

@ -1,9 +1,9 @@
codetoanalyze/c/bufferoverrun/break_continue_return.c, break_continue_return, 16, BUFFER_OVERRUN, [Offset : [0, 10] Size : [10, 10] @ codetoanalyze/c/bufferoverrun/break_continue_return.c:29:5]
codetoanalyze/c/bufferoverrun/do_while.c, do_while, 2, BUFFER_OVERRUN, [Offset : [0, +oo] Size : [10, 10] @ codetoanalyze/c/bufferoverrun/do_while.c:18:5 by call do_while_sub() ]
codetoanalyze/c/bufferoverrun/do_while.c, do_while, 3, BUFFER_OVERRUN, [Offset : [0, +oo] Size : [10, 10] @ codetoanalyze/c/bufferoverrun/do_while.c:18:5 by call do_while_sub() ]
codetoanalyze/c/bufferoverrun/do_while.c, do_while, 2, BUFFER_OVERRUN, [Offset : [0, +oo] Size : [10, 10] @ codetoanalyze/c/bufferoverrun/do_while.c:18:5 by call `do_while_sub()` ]
codetoanalyze/c/bufferoverrun/do_while.c, do_while, 3, BUFFER_OVERRUN, [Offset : [0, +oo] Size : [10, 10] @ codetoanalyze/c/bufferoverrun/do_while.c:18:5 by call `do_while_sub()` ]
codetoanalyze/c/bufferoverrun/for_loop.c, for_loop, 10, BUFFER_OVERRUN, [Offset : [0, 9] Size : [5, 10] @ codetoanalyze/c/bufferoverrun/for_loop.c:38:5]
codetoanalyze/c/bufferoverrun/function_call.c, function_call, 4, BUFFER_OVERRUN, [Offset : [100, 100] Size : [10, 10] @ codetoanalyze/c/bufferoverrun/function_call.c:17:3 by call arr_access() ]
codetoanalyze/c/bufferoverrun/function_call.c, function_call, 4, BUFFER_OVERRUN, [Offset : [20, 20] Size : [10, 10] @ codetoanalyze/c/bufferoverrun/function_call.c:18:3 by call arr_access() ]
codetoanalyze/c/bufferoverrun/function_call.c, function_call, 4, BUFFER_OVERRUN, [Offset : [20, 20] Size : [10, 10] @ codetoanalyze/c/bufferoverrun/function_call.c:18:3 by call `arr_access()` ]
codetoanalyze/c/bufferoverrun/function_call.c, function_call, 4, BUFFER_OVERRUN, [Offset : [100, 100] Size : [10, 10] @ codetoanalyze/c/bufferoverrun/function_call.c:17:3 by call `arr_access()` ]
codetoanalyze/c/bufferoverrun/goto_loop.c, goto_loop, 11, BUFFER_OVERRUN, [Offset : [10, +oo] Size : [10, 10] @ codetoanalyze/c/bufferoverrun/goto_loop.c:24:3]
codetoanalyze/c/bufferoverrun/nested_loop.c, nested_loop, 7, BUFFER_OVERRUN, [Offset : [0, 10] Size : [10, 10] @ codetoanalyze/c/bufferoverrun/nested_loop.c:20:7]
codetoanalyze/c/bufferoverrun/nested_loop_with_label.c, nested_loop_with_label, 6, BUFFER_OVERRUN, [Offset : [0, +oo] Size : [10, 10] @ codetoanalyze/c/bufferoverrun/nested_loop_with_label.c:19:5]

@ -52,7 +52,7 @@ codetoanalyze/java/eradicate/ParameterNotNullable.java, void ParameterNotNullabl
codetoanalyze/java/eradicate/ParameterNotNullable.java, void ParameterNotNullable.testThreeParameters(), 3, ERADICATE_PARAMETER_NOT_NULLABLE, [origin,`threeParameters(...)` needs a non-null value in parameter 2 but argument `null` can be null. (Origin: null constant at line 85)]
codetoanalyze/java/eradicate/ParameterNotNullable.java, void ParameterNotNullable.testThreeParameters(), 4, ERADICATE_PARAMETER_NOT_NULLABLE, [origin,`threeParameters(...)` needs a non-null value in parameter 3 but argument `null` can be null. (Origin: null constant at line 86)]
codetoanalyze/java/eradicate/PresentTest.java, Optional PresentTest$TestPresentAnnotationBasic.returnPresentBad(), 0, ERADICATE_RETURN_VALUE_NOT_PRESENT, [origin,Method `returnPresentBad()` may return an absent value but it is annotated with `@Present`. (Origin: field PresentTest$TestPresentAnnotationBasic.absent at line 47)]
codetoanalyze/java/eradicate/PresentTest.java, Optional PresentTest$TestPresentAnnotationBasic.returnPresentBad(), 1, ERADICATE_VALUE_NOT_PRESENT, [origin,The value of `PresentTest$TestPresentAnnotationBasic.absent` in the call to `get()` is not @Present. (Origin: field PresentTest$TestPresentAnnotationBasic.absent at line 47)]
codetoanalyze/java/eradicate/PresentTest.java, Optional PresentTest$TestPresentAnnotationBasic.returnPresentBad(), 1, ERADICATE_VALUE_NOT_PRESENT, [origin,The value of `PresentTest$TestPresentAnnotationBasic.absent` in the call to `get()` is not `@Present`. (Origin: field PresentTest$TestPresentAnnotationBasic.absent at line 47)]
codetoanalyze/java/eradicate/PresentTest.java, void PresentTest$TestPresentAnnotationBasic.testOptionalAbsent(), 1, ERADICATE_PARAMETER_VALUE_ABSENT, [origin,`expectPresent(...)` needs a present value in parameter 1 but argument `absent()` can be absent. (Origin: call to absent() at line 65)]
codetoanalyze/java/eradicate/PresentTest.java, void PresentTest.testPresent(Optional,Optional), 4, ERADICATE_PARAMETER_VALUE_ABSENT, [`argPresent(...)` needs a present value in parameter 1 but argument `absent` can be absent. (Origin: method parameter absent)]
codetoanalyze/java/eradicate/ReturnNotNullable.java, Object ReturnNotNullable$ConditionalAssignment.test(boolean), 0, ERADICATE_RETURN_NOT_NULLABLE, [origin,Method `test(...)` may return null but it is not annotated with `@Nullable`. (Origin: field ReturnNotNullable$ConditionalAssignment.f1 at line 146)]

Loading…
Cancel
Save