Dealing with __weak/__unsafe_unretained modifier for ivars

master
Dino Distefano 10 years ago
parent 92ceae3cf6
commit 9a93c2ed46

@ -1189,7 +1189,8 @@ let remove_opt _prop =
| Some (Some p) -> p
| _ -> Prop.prop_emp
(* Checks if cycle has fields with property attributes weak/unsafe_unretained *)
(* Checks if cycle has fields (derived from a property or directly defined as ivar) *)
(* with attributes weak/unsafe_unretained/assing *)
let cycle_has_weak_or_unretained_or_assign_field cycle =
(* returns items annotation for field fn in struct t *)
let get_item_annotation t fn =
@ -1203,10 +1204,11 @@ let cycle_has_weak_or_unretained_or_assign_field cycle =
let rec has_weak_or_unretained_or_assign params =
match params with
| [] -> false
| att::_ when Config.unsafe_unret = att || Config.weak = att || Config.assign = att -> true
| att:: _ when Config.unsafe_unret = att || Config.weak = att || Config.assign = att -> true
| _:: params' -> has_weak_or_unretained_or_assign params' in
let do_annotation (a, _) =
(a.Sil.class_name = Config.property_attributes && has_weak_or_unretained_or_assign a.Sil.parameters) in
((a.Sil.class_name = Config.property_attributes) ||
(a.Sil.class_name = Config.ivar_attributes)) && has_weak_or_unretained_or_assign a.Sil.parameters in
let rec do_cycle c =
match c with
| [] -> false

@ -372,6 +372,8 @@ let anonymous_block_num_sep = "______"
let property_attributes = "property_attributes"
let ivar_attributes = "ivar_attributes"
let unsafe_unret = "<\"Unsafe_unretained\">"
let weak = "<\"Weak\">"

@ -47,15 +47,21 @@ let get_field_www name_field fl =
(Ident.create_fieldname (Mangled.from_string "NO_FIELD_NAME") 0, Sil.Tvoid)
let rec build_sil_field tenv class_name field_name qual_type prop_atts =
let annotation_from_type t =
match t with
| Sil.Tptr(_,Sil.Pk_objc_weak) -> [Config.weak]
| Sil.Tptr(_,Sil.Pk_objc_unsafe_unretained) -> [Config.unsafe_unret]
| _ -> [] in
let fname = mk_class_field_name class_name field_name in
let typ = CTypes_decl.qual_type_to_sil_type tenv qual_type in
let item_annotations = match prop_atts with
| None -> Sil.item_annotation_empty
| None -> [({ Sil.class_name = Config.ivar_attributes; Sil.parameters = annotation_from_type typ }, true)]
| Some atts -> [({ Sil.class_name = Config.property_attributes; Sil.parameters = atts }, true)] in
fname, typ, item_annotations
(* From an ivar look for its property and if it finds it returns its attributes *)
let ivar_property curr_class ivar =
Printing.log_out "Checking if a property is defined for the ivar: '%s'@." ivar;
match ObjcProperty_decl.Property.find_property_name_from_ivar curr_class ivar with
| Some pname' ->
(Printing.log_out "Found property name from ivar: '%s'" pname';
@ -66,7 +72,7 @@ let ivar_property curr_class ivar =
with Not_found ->
Printing.log_out "Didn't find property for pname '%s'" pname';
None)
| None -> Printing.log_out "Didn't find property for ivar '%s'" ivar;
| None -> Printing.log_out "No property found for ivar '%s'@." ivar;
None
(* Given a list of declarations in an interface returns a list of fields *)
@ -78,12 +84,12 @@ let rec get_fields tenv curr_class decl_list =
let fields = get_fields tenv curr_class decl_list' in
(* Doing a post visit here. Adding Ivar after all the declaration have been visited so that *)
(* ivar names will be added in the property list. *)
Printing.log_out " ...Adding Instance Variable '%s' \n" field_name;
Printing.log_out " ...Adding Instance Variable '%s' @." field_name;
let prop_attributes = ivar_property curr_class field_name in
let (fname, typ, ia) = build_sil_field tenv class_name field_name qual_type prop_attributes in
Printing.log_out " ...Resulting sil field: (%s) with attributes:\n" ((Ident.fieldname_to_string fname) ^":"^(Sil.typ_to_string typ));
Printing.log_out " ...Resulting sil field: (%s) with attributes:@." ((Ident.fieldname_to_string fname) ^":"^(Sil.typ_to_string typ));
list_iter (fun (ia', _) ->
list_iter (fun a -> Printing.log_out " '%s' \n" a) ia'.Sil.parameters) ia;
list_iter (fun a -> Printing.log_out " '%s'@." a) ia'.Sil.parameters) ia;
(fname, typ, ia):: fields
| ObjCPropertyImplDecl(decl_info, property_impl_decl_info):: decl_list' ->

@ -92,7 +92,8 @@ let string_type_to_sil_type tenv s =
try
let t = CTypes_parser.parse (Ast_lexer.token) lexbuf in
Printing.log_out
" ...Parsed. Translated with sil TYPE '%s'@." (Sil.typ_to_string t); t
" ...Parsed. Translated with sil TYPE '%a'@." (Sil.pp_typ_full pe_text) t;
t
with Parsing.Parse_error -> (
Printing.log_stats
"\nXXXXXXX PARSE ERROR for string '%s'. RETURNING Void.TODO@.@." s;

@ -217,8 +217,7 @@ clang_type:
| VOLATILE pointer_clang_type { $2 }
| ident ANONYM_IDENT { CFrontend_utils.Printing.log_out " ...Found just an identifier modified with a protocol. Ignoring protocol!. Parsing as Named Type!\n";
Sil.Tvar (Sil.TN_typedef(Mangled.from_string $1))}
| ident { CFrontend_utils.Printing.log_out " ...Found just an identifier. Parsing as Named Type %s !\n" $1;
Sil.Tvar (Sil.TN_typedef(Mangled.from_string $1))}
| ident { Sil.Tvar (Sil.TN_typedef(Mangled.from_string $1))}
| csu_sil ident_csu { let typename=Sil.TN_csu($1, Mangled.from_string $2) in
Sil.Tvar typename }
;

@ -0,0 +1,131 @@
#import <Foundation/NSObject.h>
@class Child;
@class ChildW;
@class ChildUU;
@interface Parent : NSObject
-(void) setChild: (Child *) c;
@end
@implementation Parent {
Child *child;
}
-(void) setChild: (Child *) c {
self->child =c;
}
@end
@interface ParentW : NSObject
-(void) setChild: (ChildW *) c;
@end
@implementation ParentW {
ChildW *child;
}
-(void) setChild: (ChildW *) c {
self->child =c;
}
@end
@interface ParentUU : NSObject
-(void) setChild: (ChildUU *) c;
@end
@implementation ParentUU {
ChildUU *child;
}
-(void) setChild: (ChildUU *) c {
self->child =c;
}
@end
@interface Child : NSObject
-(void) setParent: (Parent *) p;
@end
@implementation Child {
Parent *parent;
}
-(void) setParent: (Parent *) p {
self->parent =p;
}
@end
@interface ChildW : NSObject
-(void) setParent: (ParentW *) p;
@end
@implementation ChildW {
ParentW __weak *parent;
}
-(void) setParent: (ParentW *) p {
self->parent =p;
}
@end
@interface ChildUU: NSObject
-(void) setParent: (ParentUU *) p;
@end
@implementation ChildUU {
ParentUU __unsafe_unretained *parent;
}
-(void) setParent: (ParentUU *) p {
self->parent =p;
}
@end
void strongcycle() {
Parent *parent = [[Parent alloc] init];
Child *child = [[Child alloc] init];
[parent setChild:child];
[child setParent: parent];
}
void weakcycle() {
ParentW *parent = [[ParentW alloc] init];
ChildW *child = [[ChildW alloc] init];
[parent setChild:child];
[child setParent: parent];
}
void unsafeunretainedcycle() {
ParentUU *parent = [[ParentUU alloc] init];
ChildUU *child = [[ChildUU alloc] init];
[parent setChild:child];
[child setParent: parent];
}

@ -0,0 +1,64 @@
/*
* Copyright (c) 2013- Facebook.
* All rights reserved.
*/
package endtoend.objc;
import static org.hamcrest.MatcherAssert.assertThat;
import static utils.matchers.ResultContainsExactly.containsExactly;
import static utils.matchers.ResultContainsNoErrorInMethod.doesNotContain;
import com.google.common.collect.ImmutableList;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import java.io.IOException;
import utils.DebuggableTemporaryFolder;
import utils.InferException;
import utils.InferResults;
import utils.InferRunner;
public class RetainCycle2Test {
public static final String retain_cycle_file =
"infer/tests/codetoanalyze/objc/errors/" +
"memory_leaks_benchmark/retain_cycle2.m";
private static ImmutableList<String> inferCmd;
public static final String RETAIN_CYCLE = "RETAIN_CYCLE";
@ClassRule
public static DebuggableTemporaryFolder folder =
new DebuggableTemporaryFolder();
@BeforeClass
public static void runInfer() throws InterruptedException, IOException {
inferCmd = InferRunner.createiOSInferCommandWithMLBuckets(
folder,
retain_cycle_file,
"cf",
true);
}
@Test
public void whenInferRunsOnStrongCycleThenRCIsFound()
throws InterruptedException, IOException, InferException {
InferResults inferResults = InferRunner.runInferObjC(inferCmd);
assertThat(
"Results should contain retain cycle",
inferResults,
containsExactly(
RETAIN_CYCLE,
retain_cycle_file,
new String[]{"strongcycle"}));
}
}
Loading…
Cancel
Save