|
|
|
(*
|
|
|
|
* Copyright (c) 2013 - 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
|
|
|
|
|
|
|
|
let is_modelled_static_function name =
|
[objc] Refactor modeling of CoreFoundation and CoreGraphics libraries
Summary:
The diff is very big but it's mostly removing code. It was inspired by the fact that we were getting Dead Store FPs because we were modeling some functions from CoreFoundation and CoreGraphics directly as alloc in the frontend, which caused the parameters of the function to be seen as dead. See the new test.
To deal with this, if we are going to skip the function, we model it as malloc instead. Given how many models we had for those "model as malloc" functions, I removed them to rely solely on the new mechanism.
The modeling of malloc and release was still based on the old retain count implementation, even though all we do here is a malloc/free kind of analysis. I also changed
that to be actually malloc/free which removed many Assert false in the tests. CFRelease is not exactly free though, and it's possible to use the variable afterwards. So used a custom free builtin that only cares about removing the Memory attribute and focuses on minimizing Memory Leaks FPs.
Otherwise we were translating CFBridgingRelease as a special cast, and this wasn't working. To simplify this as well, I removed all the code for the special cast, and just modeled CFBridgingRelease and CFAutorelease also as free_cf, to avoid Memory Leak false positives. I also treated the cast __bridge_transfer as a free_cf model. This means we stopped trying to report Memory Leaks on those objects.
The modeling of CoreGraph release functions was done in the frontend, but seemed simpler to also simplify that code and model all the relevant functions.
Reviewed By: sblackshear
Differential Revision: D6397150
fbshipit-source-id: b1dc636
7 years ago
|
|
|
let modelled_functions = ["_dispatch_once"; "CFAutorelease"; "CFBridgingRelease"] in
|
|
|
|
List.mem ~equal:String.equal modelled_functions name
|
|
|
|
|
|
|
|
|
[objc] Refactor modeling of CoreFoundation and CoreGraphics libraries
Summary:
The diff is very big but it's mostly removing code. It was inspired by the fact that we were getting Dead Store FPs because we were modeling some functions from CoreFoundation and CoreGraphics directly as alloc in the frontend, which caused the parameters of the function to be seen as dead. See the new test.
To deal with this, if we are going to skip the function, we model it as malloc instead. Given how many models we had for those "model as malloc" functions, I removed them to rely solely on the new mechanism.
The modeling of malloc and release was still based on the old retain count implementation, even though all we do here is a malloc/free kind of analysis. I also changed
that to be actually malloc/free which removed many Assert false in the tests. CFRelease is not exactly free though, and it's possible to use the variable afterwards. So used a custom free builtin that only cares about removing the Memory attribute and focuses on minimizing Memory Leaks FPs.
Otherwise we were translating CFBridgingRelease as a special cast, and this wasn't working. To simplify this as well, I removed all the code for the special cast, and just modeled CFBridgingRelease and CFAutorelease also as free_cf, to avoid Memory Leak false positives. I also treated the cast __bridge_transfer as a free_cf model. This means we stopped trying to report Memory Leaks on those objects.
The modeling of CoreGraph release functions was done in the frontend, but seemed simpler to also simplify that code and model all the relevant functions.
Reviewed By: sblackshear
Differential Revision: D6397150
fbshipit-source-id: b1dc636
7 years ago
|
|
|
let class_equal class_typename class_name = String.equal (Typ.Name.name class_typename) class_name
|
|
|
|
|
|
|
|
let is_builtin_expect pname =
|
|
|
|
String.equal (Typ.Procname.to_string pname) CFrontend_config.builtin_expect
|
|
|
|
|
|
|
|
|
|
|
|
let is_builtin_object_size pname =
|
|
|
|
String.equal (Typ.Procname.to_string pname) CFrontend_config.builtin_object_size
|
|
|
|
|
|
|
|
|
|
|
|
let is_std_addressof pname =
|
|
|
|
(* since std_addressof is a template function, matching it requires QualifiedCppName *)
|
|
|
|
QualifiedCppName.Match.match_qualifiers CFrontend_config.std_addressof
|
|
|
|
(Typ.Procname.get_qualifiers pname)
|
|
|
|
|
|
|
|
|
|
|
|
let is_replace_with_deref_first_arg pname =
|
|
|
|
String.equal (Typ.Procname.to_string pname) CFrontend_config.replace_with_deref_first_arg_attr
|
|
|
|
|
|
|
|
|
|
|
|
let is_modeled_builtin funct = String.equal funct CFrontend_config.builtin_memset_chk
|
|
|
|
|
|
|
|
let is_modeled_attribute attr_name =
|
|
|
|
List.mem ~equal:String.equal CFrontend_config.modeled_function_attributes attr_name
|
|
|
|
|
|
|
|
|
|
|
|
let is_assert_log_s funct =
|
|
|
|
String.equal funct CFrontend_config.assert_rtn || String.equal funct CFrontend_config.assert_fail
|
|
|
|
|| String.equal funct CFrontend_config.fbAssertWithSignalAndLogFunctionHelper
|
|
|
|
|| String.is_substring ~substring:CFrontend_config.google_MakeCheckOpString funct
|
|
|
|
|
|
|
|
|
|
|
|
let is_assert_log_method m = String.equal m CFrontend_config.google_LogMessageFatal
|
|
|
|
|
|
|
|
let is_handleFailureInMethod funct =
|
|
|
|
String.equal funct CFrontend_config.handleFailureInMethod
|
|
|
|
|| String.equal funct CFrontend_config.handleFailureInFunction
|
|
|
|
|
|
|
|
|
|
|
|
(** If the function is a builtin model, return the model, otherwise return the function *)
|
|
|
|
let is_assert_log pname =
|
|
|
|
match pname with
|
|
|
|
| Typ.Procname.ObjC_Cpp _ ->
|
|
|
|
is_assert_log_method (Typ.Procname.to_string pname)
|
|
|
|
| Typ.Procname.C _ ->
|
|
|
|
is_assert_log_s (Typ.Procname.to_string pname)
|
|
|
|
| _ ->
|
|
|
|
false
|
|
|
|
|
|
|
|
|
|
|
|
let get_predefined_ms_method condition class_name method_name method_kind mk_procname lang
|
|
|
|
arguments return_type attributes builtin =
|
|
|
|
if condition then
|
|
|
|
let procname =
|
|
|
|
match builtin with
|
|
|
|
| Some procname ->
|
|
|
|
procname
|
|
|
|
| None ->
|
|
|
|
mk_procname class_name method_name method_kind
|
|
|
|
in
|
|
|
|
let ms =
|
|
|
|
CMethodSignature.mk procname arguments return_type attributes
|
|
|
|
(CAst_utils.dummy_source_range ())
|
|
|
|
ProcAttributes.C_FUNCTION lang None None None `None
|
|
|
|
in
|
|
|
|
Some ms
|
|
|
|
else None
|
|
|
|
|
|
|
|
|
|
|
|
let get_predefined_ms_stringWithUTF8String class_name method_name mk_procname lang =
|
|
|
|
let condition =
|
|
|
|
class_equal class_name CFrontend_config.nsstring_cl
|
|
|
|
&& String.equal method_name CFrontend_config.string_with_utf8_m
|
|
|
|
in
|
[clang] [2 of 3] Dealing with custom ast expressions and flow of types in the frontend.
Summary:
This is the second of 3 stack diffs to deal with replacing the parser of types.
This diff is about general changes to the frontend to make it cope with the change. There
are two main challenges:
1. We create pieces of ast in ast_expressions, such as getters and setters. For that we create
custom types.
2. We store types in cMethod_signature for parameters and return type of functions. This was
stored as strings, but that means losing the pointer information which is vital to get the
sil types.
So this diff consists mostly of dealing with these challenges. It change the signature of
cMethod_signature and update modules accordingly.
To deal with the custom types, we build methods in ast_expressions for creating those types,
with a custom type pointer, like "internal_typeint". At the beginning of the translation we save
all these custom types in the map from type pointers to sil types that we build as we compute the
types, so that they are available later.
Another custom type that we build is a type of classes or pointer of classes based on the current
class. I found a simple way to deal with it, giving it a pointer "class_name", and then we know
how to translate those. Something I tried is to save the declaration of the current class and pass
that declaration around, but somehow that lead to pref regression, so I removed it in favor of this
more lightweight version.
9 years ago
|
|
|
let id_type = Ast_expressions.create_id_type in
|
|
|
|
let char_star_type =
|
|
|
|
Ast_expressions.create_char_star_type ~quals:(Typ.mk_type_quals ~is_const:true ()) ()
|
|
|
|
in
|
|
|
|
let args = [(Mangled.from_string "x", char_star_type)] in
|
|
|
|
get_predefined_ms_method condition class_name method_name Typ.Procname.ObjC_Cpp.ObjCClassMethod
|
|
|
|
mk_procname lang args id_type [] None
|
|
|
|
|
|
|
|
|
|
|
|
let get_predefined_ms_is_kind_of_class class_name method_name mk_procname lang =
|
|
|
|
let condition = String.equal method_name CFrontend_config.is_kind_of_class in
|
|
|
|
let class_type = Ast_expressions.create_class_qual_type class_name in
|
|
|
|
let args = [(Mangled.from_string CFrontend_config.self, class_type)] in
|
|
|
|
get_predefined_ms_method condition class_name method_name
|
|
|
|
Typ.Procname.ObjC_Cpp.ObjCInstanceMethod mk_procname lang args Ast_expressions.create_BOOL_type
|
|
|
|
[] (Some BuiltinDecl.__instanceof)
|
|
|
|
|
|
|
|
|
|
|
|
let get_predefined_model_method_signature class_name method_name mk_procname lang =
|
|
|
|
let next_predefined f = function Some _ as x -> x | None -> f method_name mk_procname lang in
|
|
|
|
None |> next_predefined (get_predefined_ms_stringWithUTF8String class_name)
|
|
|
|
|> next_predefined (get_predefined_ms_is_kind_of_class class_name)
|