[pulse] Model __bridge_transfer

Summary:
This translates the construct `ObjCBridgedCastExpr` when the cast_kind is `OBC_BridgeTransfer`, or in syntax, the cast (`__bridge_transfer`).
This cast means that the object is passed from manual memory management to ARC, so one doesn't need to call `release` manually. It is important to model this to avoid false positives.

It translates it as a builtin that we then model in Pulse, the same way we modelled `CFBridgingRelease` which does the same thing.

The name of the builtin is `__free_cf` which is not ideal but I left it like that for compatibility with biabduction. We can change it once we remove this check from biabduction.

update-submodule: facebook-clang-plugins

Reviewed By: jvillard

Differential Revision: D21176337

fbshipit-source-id: 736ceeb9b
master
Dulma Churchill 5 years ago committed by Facebook GitHub Bot
parent 4ad899b37e
commit fa13577695

@ -1 +1 @@
Subproject commit 48d27425e9e9e8d0bace06e9e7893cb23b21a2a4
Subproject commit a9c545fecae6cc447c28d4535488986941858ab1

@ -193,7 +193,5 @@ module Core_foundation_model = struct
&& (String.is_substring ~substring:create funct || String.is_substring ~substring:copy funct)
end
let is_core_lib_type typ = Core_foundation_model.is_core_lib_type typ
let is_malloc_model return_type pname =
Core_foundation_model.is_core_lib_create return_type (Procname.to_string pname)

@ -10,6 +10,4 @@ open! IStd
(** This module models special c struct types from the Apple's Core Foundation libraries for which
there are particular rules for memory management. *)
val is_core_lib_type : Typ.t -> bool
val is_malloc_model : Typ.t -> Procname.t -> bool

@ -2557,7 +2557,8 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
(** Cast expression are treated the same apart from the cast operation kind *)
and cast_exprs_trans trans_state stmt_info stmt_list expr_info cast_expr_info =
and cast_exprs_trans trans_state stmt_info stmt_list expr_info ?objc_bridge_cast_kind
cast_expr_info =
let context = trans_state.context in
L.(debug Capture Verbose)
" priority node free = '%s'@\n@."
@ -2576,7 +2577,7 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
let cast_kind = cast_expr_info.Clang_ast_t.cei_cast_kind in
let exp_typ = res_trans_stmt.return in
(* This gives the difference among cast operations kind *)
let cast_inst, cast_exp = cast_operation cast_kind exp_typ typ sil_loc in
let cast_inst, cast_exp = cast_operation ?objc_bridge_cast_kind cast_kind exp_typ typ sil_loc in
{ res_trans_stmt with
control= {res_trans_stmt.control with instrs= res_trans_stmt.control.instrs @ cast_inst}
; return= cast_exp }
@ -3530,7 +3531,6 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
pseudoObjectExpr_trans trans_state stmt_list
| UnaryExprOrTypeTraitExpr (_, _, _, unary_expr_or_type_trait_expr_info) ->
unaryExprOrTypeTraitExpr_trans trans_state unary_expr_or_type_trait_expr_info
| ObjCBridgedCastExpr (stmt_info, stmt_list, expr_info, cast_kind, _)
| ImplicitCastExpr (stmt_info, stmt_list, expr_info, cast_kind)
| BuiltinBitCastExpr (stmt_info, stmt_list, expr_info, cast_kind, _)
| CStyleCastExpr (stmt_info, stmt_list, expr_info, cast_kind, _)
@ -3539,6 +3539,9 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s
| CXXStaticCastExpr (stmt_info, stmt_list, expr_info, cast_kind, _, _)
| CXXFunctionalCastExpr (stmt_info, stmt_list, expr_info, cast_kind, _) ->
cast_exprs_trans trans_state stmt_info stmt_list expr_info cast_kind
| ObjCBridgedCastExpr (stmt_info, stmt_list, expr_info, cast_kind, _, objc_bridge_cast_ei) ->
let objc_bridge_cast_kind = objc_bridge_cast_ei.Clang_ast_t.obcei_cast_kind in
cast_exprs_trans trans_state stmt_info stmt_list expr_info ~objc_bridge_cast_kind cast_kind
| IntegerLiteral (_, _, expr_info, integer_literal_info) ->
integerLiteral_trans trans_state expr_info integer_literal_info
| OffsetOfExpr (stmt_info, _, expr_info, offset_of_expr_info) ->

@ -424,7 +424,7 @@ let dereference_value_from_result ?(strip_pointer = false) source_range sil_loc
; return= (cast_exp, cast_typ) }
let cast_operation cast_kind ((exp, typ) as exp_typ) cast_typ sil_loc =
let cast_operation ?objc_bridge_cast_kind cast_kind ((exp, typ) as exp_typ) cast_typ sil_loc =
match cast_kind with
| `NoOp | `DerivedToBase | `UncheckedDerivedToBase ->
(* These casts ignore change of type *)
@ -436,10 +436,6 @@ let cast_operation cast_kind ((exp, typ) as exp_typ) cast_typ sil_loc =
| `BitCast | `IntegralCast | `IntegralToBoolean ->
(* This is treated as a nop by returning the same expressions exps*)
([], (exp, cast_typ))
| `CPointerToObjCPointerCast when Objc_models.is_core_lib_type typ ->
(* Translation of __bridge_transfer *)
let instr = create_call_to_free_cf sil_loc exp typ in
([instr], (exp, cast_typ))
| `LValueToRValue ->
(* Takes an LValue and allow it to use it as RValue. *)
(* So we assign the LValue to a temp and we pass it to the parent.*)
@ -457,11 +453,25 @@ let cast_operation cast_kind ((exp, typ) as exp_typ) cast_typ sil_loc =
Sil.Call ((no_id, cast_typ), skip_builtin, args, sil_loc, CallFlags.default)
in
([call_instr], (exp, cast_typ))
| _ ->
L.(debug Capture Verbose)
"@\nWARNING: Missing translation for Cast Kind %s. The construct has been ignored...@\n"
(Clang_ast_j.string_of_cast_kind cast_kind) ;
([], (exp, cast_typ))
| _ -> (
match objc_bridge_cast_kind with
| Some `OBC_BridgeTransfer ->
let instr = create_call_to_free_cf sil_loc exp typ in
([instr], (exp, cast_typ))
| Some cast_kind ->
L.debug Capture Verbose
"@\n\
WARNING: Missing translation for ObjC Bridge Cast Kind %a. The construct has been \
ignored...@\n"
(Pp.of_string ~f:Clang_ast_j.string_of_obj_c_bridge_cast_kind)
cast_kind ;
([], (exp, cast_typ))
| _ ->
L.debug Capture Verbose
"@\nWARNING: Missing translation for Cast Kind %a. The construct has been ignored...@\n"
(Pp.of_string ~f:Clang_ast_j.string_of_cast_kind)
cast_kind ;
([], (exp, cast_typ)) )
let trans_assertion_failure sil_loc (context : CContext.t) =

@ -90,7 +90,12 @@ val dereference_value_from_result :
assigned to it *)
val cast_operation :
Clang_ast_t.cast_kind -> Exp.t * Typ.t -> Typ.t -> Location.t -> Sil.instr list * (Exp.t * Typ.t)
?objc_bridge_cast_kind:Clang_ast_t.obj_c_bridge_cast_kind
-> Clang_ast_t.cast_kind
-> Exp.t * Typ.t
-> Typ.t
-> Location.t
-> Sil.instr list * (Exp.t * Typ.t)
val trans_assertion : trans_state -> Location.t -> trans_result

@ -675,6 +675,7 @@ module ProcNameDispatcher = struct
; -"CFRelease" <>$ capt_arg_payload $--> C.free
; -"CFAutorelease" <>$ capt_arg_payload $--> C.free
; -"CFBridgingRelease" <>$ capt_arg_payload $--> C.cf_bridging_release
; +match_builtin BuiltinDecl.__free_cf <>$ capt_arg_payload $--> C.cf_bridging_release
; +PatternMatch.ObjectiveC.is_modelled_as_alloc &++> C.malloc_not_null
; +PatternMatch.ObjectiveC.is_modelled_as_free <>$ capt_arg_payload $--> C.free ]
end

@ -71,6 +71,7 @@ codetoanalyze/objc/errors/subtyping/KindOfClassExample.m, shouldThrowDivideByZer
codetoanalyze/objc/errors/subtyping/KindOfClassExample.m, shouldThrowDivideByZero2, 2, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure shouldThrowDivideByZero2(),start of procedure init,return from a call to Base::init,start of procedure returnsZero2(),Taking false branch,return from a call to returnsZero2]
codetoanalyze/objc/errors/subtyping/KindOfClassExample.m, shouldThrowDivideByZero3, 3, DIVIDE_BY_ZERO, no_bucket, ERROR, [start of procedure shouldThrowDivideByZero3(),start of procedure init,return from a call to Derived::init,Taking true branch]
codetoanalyze/objc/errors/variadic_methods/premature_nil_termination.m, PrematureNilTermA::nilInArrayWithObjects, 5, PREMATURE_NIL_TERMINATION_ARGUMENT, B1, ERROR, [start of procedure nilInArrayWithObjects]
codetoanalyze/objc/shared/memory_leaks_benchmark/TollBridgeExample.m, TollBridgeExample::bridge, 2, MEMORY_LEAK, no_bucket, ERROR, [start of procedure bridge]
codetoanalyze/objc/errors/memory_leaks_benchmark/CoreVideoExample.m, CoreVideoExample::cvpixelbuffer_not_released_leak, 1, MEMORY_LEAK, no_bucket, ERROR, [start of procedure cvpixelbuffer_not_released_leak]
codetoanalyze/objc/errors/memory_leaks_benchmark/NSData_models_tests.m, NSData_models_tests::macForIV:, 2, MEMORY_LEAK, no_bucket, ERROR, [start of procedure macForIV:]
codetoanalyze/objc/errors/memory_leaks_benchmark/NSString_models_tests.m, StringInitA::hexStringValue, 11, MEMORY_LEAK, no_bucket, ERROR, [start of procedure hexStringValue,Skipping CFStringCreateWithBytesNoCopy(): method has no implementation,Taking false branch]

@ -10,6 +10,9 @@
typedef struct ABFDataRef {
} ABFDataRef;
@interface ABFData
@end
ABFDataRef* ABFDataCreate(size_t size);
void ABFRelease(ABFDataRef*);
@ -27,4 +30,8 @@ void ABFRelease(ABFDataRef*);
ABFRelease(someData);
}
- (void)bridge_no_leak_good {
ABFData* someData = (__bridge_transfer ABFData*)ABFDataCreate(4);
}
@end

@ -5,7 +5,7 @@
TESTS_DIR = ../../..
CLANG_OPTIONS = -c $(OBJC_CLANG_OPTIONS)
CLANG_OPTIONS = -c $(OBJC_CLANG_OPTIONS) -fobjc-arc
INFER_OPTIONS = --pulse-only --debug-exceptions --project-root $(TESTS_DIR) \
--pulse-model-alloc-pattern "AB[IF].*Create.*\|CFLocaleCreate" \
--pulse-model-free-pattern ABFRelease

@ -62,4 +62,9 @@
CFLocaleRef nameRef = CFLocaleCreate(NULL, NULL);
}
- (void)bridge_transfer_no_leak_good {
CFLocaleRef nameRef = CFLocaleCreate(NULL, NULL);
NSLocale* locale = (__bridge_transfer NSLocale*)nameRef;
}
@end

@ -33,11 +33,11 @@ digraph cfg {
"_readHTTPHeader#TollBridgeExample#instance.3d37ce88cf13750e89ba404865a70554_2" [label="2: Exit TollBridgeExample::_readHTTPHeader \n " color=yellow style=filled]
"_readHTTPHeader#TollBridgeExample#instance.3d37ce88cf13750e89ba404865a70554_3" [label="3: Call _fun_CFBridgingRelease \n n$8=*&ref:__CFDictionary const * [line 35, column 21]\n n$9=_fun_CFBridgingRelease(n$8:void const *) [line 35, column 3]\n " shape="box"]
"_readHTTPHeader#TollBridgeExample#instance.3d37ce88cf13750e89ba404865a70554_3" [label="3: Call _fun_CFBridgingRelease \n n$6=*&ref:__CFDictionary const * [line 35, column 21]\n n$7=_fun_CFBridgingRelease(n$6:void const *) [line 35, column 3]\n " shape="box"]
"_readHTTPHeader#TollBridgeExample#instance.3d37ce88cf13750e89ba404865a70554_3" -> "_readHTTPHeader#TollBridgeExample#instance.3d37ce88cf13750e89ba404865a70554_2" ;
"_readHTTPHeader#TollBridgeExample#instance.3d37ce88cf13750e89ba404865a70554_4" [label="4: DeclStmt \n VARIABLE_DECLARED(ref:__CFDictionary const *); [line 34, column 3]\n n$10=_fun_CFHTTPMessageCopyAllHeaderFields(null:__CFHTTPMessage*) [line 34, column 25]\n *&ref:__CFDictionary const *=n$10 [line 34, column 3]\n " shape="box"]
"_readHTTPHeader#TollBridgeExample#instance.3d37ce88cf13750e89ba404865a70554_4" [label="4: DeclStmt \n VARIABLE_DECLARED(ref:__CFDictionary const *); [line 34, column 3]\n n$8=_fun_CFHTTPMessageCopyAllHeaderFields(null:__CFHTTPMessage*) [line 34, column 25]\n *&ref:__CFDictionary const *=n$8 [line 34, column 3]\n " shape="box"]
"_readHTTPHeader#TollBridgeExample#instance.3d37ce88cf13750e89ba404865a70554_4" -> "_readHTTPHeader#TollBridgeExample#instance.3d37ce88cf13750e89ba404865a70554_3" ;
@ -48,11 +48,11 @@ digraph cfg {
"brideRetained#TollBridgeExample#instance.de039e838ea3246eff789fdc0d11405c_2" [label="2: Exit TollBridgeExample::brideRetained \n " color=yellow style=filled]
"brideRetained#TollBridgeExample#instance.de039e838ea3246eff789fdc0d11405c_3" [label="3: DeclStmt \n VARIABLE_DECLARED(a:__CFLocale const *); [line 29, column 3]\n n$6=*&observer:objc_object* [line 29, column 50]\n *&a:__CFLocale const *=n$6 [line 29, column 3]\n " shape="box"]
"brideRetained#TollBridgeExample#instance.de039e838ea3246eff789fdc0d11405c_3" [label="3: DeclStmt \n VARIABLE_DECLARED(a:__CFLocale const *); [line 29, column 3]\n n$4=*&observer:objc_object* [line 29, column 50]\n *&a:__CFLocale const *=n$4 [line 29, column 3]\n " shape="box"]
"brideRetained#TollBridgeExample#instance.de039e838ea3246eff789fdc0d11405c_3" -> "brideRetained#TollBridgeExample#instance.de039e838ea3246eff789fdc0d11405c_2" ;
"brideRetained#TollBridgeExample#instance.de039e838ea3246eff789fdc0d11405c_4" [label="4: DeclStmt \n VARIABLE_DECLARED(observer:objc_object*); [line 28, column 3]\n n$7=_fun___objc_alloc_no_fail(sizeof(t=NSLocale):unsigned long) [line 28, column 17]\n *&observer:objc_object*=n$7 [line 28, column 3]\n " shape="box"]
"brideRetained#TollBridgeExample#instance.de039e838ea3246eff789fdc0d11405c_4" [label="4: DeclStmt \n VARIABLE_DECLARED(observer:objc_object*); [line 28, column 3]\n n$5=_fun___objc_alloc_no_fail(sizeof(t=NSLocale):unsigned long) [line 28, column 17]\n *&observer:objc_object*=n$5 [line 28, column 3]\n " shape="box"]
"brideRetained#TollBridgeExample#instance.de039e838ea3246eff789fdc0d11405c_4" -> "brideRetained#TollBridgeExample#instance.de039e838ea3246eff789fdc0d11405c_3" ;
@ -63,11 +63,11 @@ digraph cfg {
"bridge#TollBridgeExample#instance.fadd5a014118113c960fa1a6e3ff27ba_2" [label="2: Exit TollBridgeExample::bridge \n " color=yellow style=filled]
"bridge#TollBridgeExample#instance.fadd5a014118113c960fa1a6e3ff27ba_3" [label="3: DeclStmt \n VARIABLE_DECLARED(a:NSLocale*); [line 24, column 3]\n n$3=*&nameRef:__CFLocale const * [line 24, column 37]\n n$4=_fun___free_cf(n$3:__CFLocale const *) [line 24, column 17]\n *&a:NSLocale*=n$3 [line 24, column 3]\n " shape="box"]
"bridge#TollBridgeExample#instance.fadd5a014118113c960fa1a6e3ff27ba_3" [label="3: DeclStmt \n VARIABLE_DECLARED(a:NSLocale*); [line 24, column 3]\n n$2=*&nameRef:__CFLocale const * [line 24, column 37]\n *&a:NSLocale*=n$2 [line 24, column 3]\n " shape="box"]
"bridge#TollBridgeExample#instance.fadd5a014118113c960fa1a6e3ff27ba_3" -> "bridge#TollBridgeExample#instance.fadd5a014118113c960fa1a6e3ff27ba_2" ;
"bridge#TollBridgeExample#instance.fadd5a014118113c960fa1a6e3ff27ba_4" [label="4: DeclStmt \n VARIABLE_DECLARED(nameRef:__CFLocale const *); [line 23, column 3]\n n$5=_fun_CFLocaleCreate(null:__CFAllocator const *,null:__CFString const *) [line 23, column 25]\n *&nameRef:__CFLocale const *=n$5 [line 23, column 3]\n " shape="box"]
"bridge#TollBridgeExample#instance.fadd5a014118113c960fa1a6e3ff27ba_4" [label="4: DeclStmt \n VARIABLE_DECLARED(nameRef:__CFLocale const *); [line 23, column 3]\n n$3=_fun_CFLocaleCreate(null:__CFAllocator const *,null:__CFString const *) [line 23, column 25]\n *&nameRef:__CFLocale const *=n$3 [line 23, column 3]\n " shape="box"]
"bridge#TollBridgeExample#instance.fadd5a014118113c960fa1a6e3ff27ba_4" -> "bridge#TollBridgeExample#instance.fadd5a014118113c960fa1a6e3ff27ba_3" ;
@ -78,11 +78,11 @@ digraph cfg {
"bridgeTransfer#TollBridgeExample#instance.d0065913beb197e891ef0d8a0bb81b38_2" [label="2: Exit TollBridgeExample::bridgeTransfer \n " color=yellow style=filled]
"bridgeTransfer#TollBridgeExample#instance.d0065913beb197e891ef0d8a0bb81b38_3" [label="3: DeclStmt \n VARIABLE_DECLARED(a:NSLocale*); [line 19, column 3]\n n$0=*&nameRef:__CFLocale const * [line 19, column 46]\n n$1=_fun___free_cf(n$0:__CFLocale const *) [line 19, column 17]\n *&a:NSLocale*=n$0 [line 19, column 3]\n " shape="box"]
"bridgeTransfer#TollBridgeExample#instance.d0065913beb197e891ef0d8a0bb81b38_3" [label="3: DeclStmt \n VARIABLE_DECLARED(a:NSLocale*); [line 19, column 3]\n n$0=*&nameRef:__CFLocale const * [line 19, column 46]\n *&a:NSLocale*=n$0 [line 19, column 3]\n " shape="box"]
"bridgeTransfer#TollBridgeExample#instance.d0065913beb197e891ef0d8a0bb81b38_3" -> "bridgeTransfer#TollBridgeExample#instance.d0065913beb197e891ef0d8a0bb81b38_2" ;
"bridgeTransfer#TollBridgeExample#instance.d0065913beb197e891ef0d8a0bb81b38_4" [label="4: DeclStmt \n VARIABLE_DECLARED(nameRef:__CFLocale const *); [line 18, column 3]\n n$2=_fun_CFLocaleCreate(null:__CFAllocator const *,null:__CFString const *) [line 18, column 25]\n *&nameRef:__CFLocale const *=n$2 [line 18, column 3]\n " shape="box"]
"bridgeTransfer#TollBridgeExample#instance.d0065913beb197e891ef0d8a0bb81b38_4" [label="4: DeclStmt \n VARIABLE_DECLARED(nameRef:__CFLocale const *); [line 18, column 3]\n n$1=_fun_CFLocaleCreate(null:__CFAllocator const *,null:__CFString const *) [line 18, column 25]\n *&nameRef:__CFLocale const *=n$1 [line 18, column 3]\n " shape="box"]
"bridgeTransfer#TollBridgeExample#instance.d0065913beb197e891ef0d8a0bb81b38_4" -> "bridgeTransfer#TollBridgeExample#instance.d0065913beb197e891ef0d8a0bb81b38_3" ;

Loading…
Cancel
Save