diff --git a/infer/models/objc/src/NSNotificationCenter.m b/infer/models/objc/src/NSNotificationCenter.m new file mode 100644 index 000000000..e89e39804 --- /dev/null +++ b/infer/models/objc/src/NSNotificationCenter.m @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016 - 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. + */ + +#import + +void __set_observer_attribute(id); +void __set_unsubscribed_observer_attribute(id); + +@interface NSNotificationCenter : NSObject + +- (void) addObserver:(id)notificationObserver + selector:(SEL)notificationSelector + name:(NSString *)notificationName + object:(id)notificationSender; + +- (void) removeObserver:(id)notificationObserver; + +- (void) removeObserver:(id)notificationObserver + name:(NSString *)notificationName + object:(id)notificationSender; +@end + +@implementation NSNotificationCenter + + +- (void) addObserver:(id)notificationObserver + selector:(SEL)notificationSelector + name:(NSString *)notificationName + object:(id)notificationSender +{ + __set_observer_attribute(notificationObserver); +} + +- (void) removeObserver:(id)notificationObserver +{ + __set_unsubscribed_observer_attribute(notificationObserver); +} + +- (void) removeObserver:(id)notificationObserver + name:(NSString *)notificationName + object:(id)notificationSender +{ + __set_unsubscribed_observer_attribute(notificationObserver); +} + +@end diff --git a/infer/src/backend/sil.ml b/infer/src/backend/sil.ml index 99b0be59c..22899b252 100644 --- a/infer/src/backend/sil.ml +++ b/infer/src/backend/sil.ml @@ -626,6 +626,10 @@ and attribute = | Aobjc_null of exp (** value was returned from a call to the given procedure *) | Aretval of Procname.t + (** denotes an object registered as an observers to a notification center *) + | Aobserver + (** denotes an object unsubscribed from observers of a notification center *) + | Aunsubscribed_observer (** Categories of attributes *) and attribute_category = @@ -637,6 +641,7 @@ and attribute_category = | ACobjc_null | ACundef | ACretval + | ACobserver (** Constants *) and const = @@ -1180,6 +1185,8 @@ let attribute_to_category att = | Aobjc_null _ -> ACobjc_null | Aretval _ -> ACretval | Aundef _ -> ACundef + | Aobserver + | Aunsubscribed_observer -> ACobserver let attr_is_undef = function | Aundef _ -> true @@ -1398,6 +1405,12 @@ and attribute_compare (att1 : attribute) (att2 : attribute) : int = | Aretval pn1, Aretval pn2 -> Procname.compare pn1 pn2 | Aretval _, _ -> -1 | _, Aretval _ -> 1 + | Aobserver, Aobserver -> 0 + | Aobserver, _ -> -1 + | _, Aobserver -> 1 + | Aunsubscribed_observer, Aunsubscribed_observer -> 0 + | Aunsubscribed_observer, _ -> -1 + | _, Aunsubscribed_observer -> 1 (** Compare epressions. Variables come before other expressions. *) and exp_compare (e1 : exp) (e2 : exp) : int = @@ -1962,6 +1975,8 @@ and attribute_to_string pe = function | _ -> "" in "OBJC_NULL["^ info_s ^"]" | Aretval pn -> "RET" ^ str_binop pe Lt ^ Procname.to_string pn ^ str_binop pe Gt + | Aobserver -> "OBSERVER" + | Aunsubscribed_observer -> "UNSUBSCRIBED_OBSERVER" and pp_const pe f = function | Cint i -> Int.pp f i diff --git a/infer/src/backend/sil.mli b/infer/src/backend/sil.mli index 1caa2b808..2d7212df8 100644 --- a/infer/src/backend/sil.mli +++ b/infer/src/backend/sil.mli @@ -256,6 +256,10 @@ and attribute = | Aobjc_null of exp (** value was returned from a call to the given procedure *) | Aretval of Procname.t + (** denotes an object registered as an observers to a notification center *) + | Aobserver + (** denotes an object unsubscribed from observers of a notification center *) + | Aunsubscribed_observer (** Categories of attributes *) and attribute_category = @@ -267,6 +271,7 @@ and attribute_category = | ACobjc_null | ACundef | ACretval + | ACobserver (** Constants *) and const = diff --git a/infer/src/backend/symExec.ml b/infer/src/backend/symExec.ml index 824efb7ab..9a9492b79 100644 --- a/infer/src/backend/symExec.ml +++ b/infer/src/backend/symExec.ml @@ -1999,47 +1999,6 @@ module ModelBuiltins = struct set_resource_attribute prop path n_lexp loc (Sil.Rmemory Sil.Mnew) | _ -> raise (Exceptions.Wrong_argument_number __POS__) - (** Set the attibute of the value as tainted *) - let execute___set_taint_attribute cfg pdesc instr tenv _prop path ret_ids args callee_name loc - : Builtin.ret_typ = - match args, ret_ids with - | [(lexp, typ)], _ -> - let pname = Cfg.Procdesc.get_proc_name pdesc in - let n_lexp, prop = exp_norm_check_arith pname _prop lexp in - [(Prop.add_or_replace_exp_attribute prop n_lexp (Sil.Ataint pname), path)] - | _ -> raise (Exceptions.Wrong_argument_number __POS__) - - (** Set the attibute of the value as untainted *) - let execute___set_untaint_attribute cfg pdesc instr tenv _prop path ret_ids args callee_name loc - : Builtin.ret_typ = - match args, ret_ids with - | [(lexp, typ)], _ -> - let pname = Cfg.Procdesc.get_proc_name pdesc in - let n_lexp, prop = exp_norm_check_arith pname _prop lexp in - [(Prop.add_or_replace_exp_attribute prop n_lexp (Sil.Auntaint), path)] - | _ -> raise (Exceptions.Wrong_argument_number __POS__) - - (** Set the attibute of the value as locked*) - let execute___set_locked_attribute cfg pdesc instr tenv _prop path ret_ids args callee_name loc - : Builtin.ret_typ = - match args, ret_ids with - | [(lexp, typ)], _ -> - let pname = Cfg.Procdesc.get_proc_name pdesc in - let n_lexp, prop = exp_norm_check_arith pname _prop lexp in - [(Prop.add_or_replace_exp_attribute prop n_lexp (Sil.Alocked), path)] - | _ -> raise (Exceptions.Wrong_argument_number __POS__) - - (** Set the attibute of the value as unlocked*) - let execute___set_unlocked_attribute cfg pdesc instr tenv _prop path ret_ids args callee_name loc - : Builtin.ret_typ = - match args, ret_ids with - | [(lexp, typ)], _ -> - let pname = Cfg.Procdesc.get_proc_name pdesc in - let n_lexp, prop = exp_norm_check_arith pname _prop lexp in - [(Prop.add_or_replace_exp_attribute prop n_lexp (Sil.Aunlocked), path)] - | _ -> raise (Exceptions.Wrong_argument_number __POS__) - - (** report an error if [lexp] is tainted; otherwise, add untained([lexp]) as a precondition *) let execute___check_untainted cfg pdesc instr tenv prop path ret_ids args callee_pname loc : Builtin.ret_typ = @@ -2225,6 +2184,23 @@ module ModelBuiltins = struct IList.fold_left call_release [(prop, path)] autoreleased_objects else execute___no_op _prop path + (** Set attibute att *) + let execute___set_attr att cfg pdesc instr tenv _prop path ret_ids args callee_name loc + : Builtin.ret_typ = + match args with + | [(lexp, typ)] -> + let pname = Cfg.Procdesc.get_proc_name pdesc in + let n_lexp, prop = exp_norm_check_arith pname _prop lexp in + [(Prop.add_or_replace_exp_attribute prop n_lexp att, path)] + | _ -> raise (Exceptions.Wrong_argument_number __POS__) + + (** Set the attibute of the value as tainted *) + let execute___set_taint_attribute cfg pdesc instr tenv _prop path ret_ids args callee_name loc + : Builtin.ret_typ = + let pname = Cfg.Procdesc.get_proc_name pdesc in + execute___set_attr (Sil.Ataint pname) + cfg pdesc instr tenv _prop path ret_ids args callee_name loc + let execute___objc_cast cfg pdesc instr tenv _prop path ret_ids args callee_pname loc : Builtin.ret_typ = match args with @@ -2528,6 +2504,13 @@ module ModelBuiltins = struct let __set_lock_attribute = Builtin.register "__set_lock_attribute" execute___set_lock_attribute (* set the attribute of the parameter as file *) let __set_mem_attribute = Builtin.register "__set_mem_attribute" execute___set_mem_attribute (* set the attribute of the parameter as memory *) let __set_autorelease_attribute = Builtin.register "__set_autorelease_attribute" execute___set_autorelease_attribute (* set the attribute of the parameter as autorelease *) + (* set the observer attribute of the parameter *) + let __set_observer_attribute = + Builtin.register "__set_observer_attribute" (execute___set_attr Sil.Aobserver) + (* set the unregistered observer attribute of the parameter *) + let __set_unsubscribed_observer_attribute = + Builtin.register "__set_unsubscribed_observer_attribute" + (execute___set_attr Sil.Aunsubscribed_observer) let __objc_release_autorelease_pool = Builtin.register "__objc_release_autorelease_pool" execute___release_autorelease_pool (* set the attribute of the parameter as autorelease *) let __split_get_nth = Builtin.register "__split_get_nth" execute___split_get_nth (* splits a string given a separator and returns the nth string *) @@ -2540,11 +2523,11 @@ module ModelBuiltins = struct (* set the attribute of the parameter as tainted *) let _ = Builtin.register "__set_taint_attribute" execute___set_taint_attribute (* set the attribute of the parameter as untainted *) - let _ = Builtin.register "__set_untaint_attribute" execute___set_untaint_attribute + let _ = Builtin.register "__set_untaint_attribute" (execute___set_attr Sil.Auntaint) (* set the attribute of the parameter as locked *) - let _ = Builtin.register "__set_locked_attribute" execute___set_locked_attribute + let _ = Builtin.register "__set_locked_attribute" (execute___set_attr Sil.Alocked) (* set the attribute of the parameter as unlocked *) - let _ = Builtin.register "__set_unlocked_attribute" execute___set_unlocked_attribute + let _ = Builtin.register "__set_unlocked_attribute" (execute___set_attr Sil.Aunlocked) let _ = Builtin.register "__check_untainted" execute___check_untainted (* report a taint error if the parameter is tainted, and assume it is untainted afterward *) let __objc_retain = Builtin.register "__objc_retain" execute___objc_retain (* objective-c "retain" *) let __objc_release = Builtin.register "__objc_release" execute___objc_release (* objective-c "release" *)