From a9e2322bda6e9e5303b08d064005eddd4b1b68fe Mon Sep 17 00:00:00 2001 From: Sungkeun Cho Date: Mon, 28 Sep 2020 06:10:09 -0700 Subject: [PATCH] [closure] Keep closure parameter in specialized procedure Summary: This diff keeps closure parameters in closure-specializated procedures. What the closure-specialization is doing is a propagation of concrete closures. For example, it translates: ``` foo(block b) { b(); } goo() { foo(^{...}); } ``` to ``` foo_new() { (^{...})(); } goo() { foo_new(); } ``` However, if `foo` addresses `b` as a normal value like ``` foo(block b) { block c = b; } ``` this is translated to ``` foo_new() { block c = b; } ``` Note that the closure parameter of `foo` is removed, thus `b` becomes a free variable. Not good. To avoid the situation, this diff keeps the closure parameters intact. Reviewed By: da319 Differential Revision: D23905580 fbshipit-source-id: 014989fbf --- infer/src/clang/CCallSpecializedWithClosures.ml | 1 + infer/src/cost/costAutoreleaseModels.ml | 3 ++- .../codetoanalyze/objc/frontend/block/retain_cycle.m.dot | 2 +- .../block/specialized_method_with_block_params.m.dot | 8 ++++---- .../objc/shared/block/Blocks_as_parameters.m.dot | 2 +- .../tests/codetoanalyze/objc/shared/block/block-it.m.dot | 2 +- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/infer/src/clang/CCallSpecializedWithClosures.ml b/infer/src/clang/CCallSpecializedWithClosures.ml index d510ccbe8..9935f1e49 100644 --- a/infer/src/clang/CCallSpecializedWithClosures.ml +++ b/infer/src/clang/CCallSpecializedWithClosures.ml @@ -56,6 +56,7 @@ let formals_actuals_new_set map = (fun formal actual set -> match actual with | Exp.Closure closure, _ -> + let set = FormalsActualsSet.add {formal; actual} set in List.fold_left closure.Exp.captured_vars ~init:set ~f:(fun set (exp, var, typ, _) -> let formal_annot = {formal_type= (Pvar.build_formal_from_pvar var, typ); formal_annot= Annot.Item.empty} diff --git a/infer/src/cost/costAutoreleaseModels.ml b/infer/src/cost/costAutoreleaseModels.ml index d84a4778b..f8b147949 100644 --- a/infer/src/cost/costAutoreleaseModels.ml +++ b/infer/src/cost/costAutoreleaseModels.ml @@ -50,7 +50,8 @@ module Call = struct [ +PatternMatch.ObjectiveC.implements "NSObject" &:: "autorelease" &--> unit_cost ; -"CFAutorelease" &--> unit_cost ; +PatternMatch.ObjectiveC.implements "NSArray" - &:: "indexOfObjectPassingTest:" $ capt_exp $--> NSArray.index_of_object_passing_test + &:: "indexOfObjectPassingTest:" $ capt_exp $+ any_arg + $--> NSArray.index_of_object_passing_test ; +PatternMatch.ObjectiveC.implements "NSKeyedUnarchiver" &:: "initForReadingFromData:error:" &--> unit_cost ; +PatternMatch.ObjectiveC.implements "NSKeyedUnarchiver" diff --git a/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.m.dot b/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.m.dot index 416119e31..ca5e9f930 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.m.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/retain_cycle.m.dot @@ -52,7 +52,7 @@ digraph cfg { "capture#A#instance.d411336575e4bf632a1828f5f5979726_2" [label="2: Exit A.capture \n " color=yellow style=filled] -"capture#A#instance.d411336575e4bf632a1828f5f5979726_3" [label="3: Message Call: sHandler: \n n$3=*&self:A* [line 45, column 4]\n n$4=*n$3._b:B* [line 45, column 4]\n n$0=*&self:A* [line 45, column 16]\n n$5=_fun_B.sHandler:[objc_blockA.capture_1](n$0:A*,n$4:B*) virtual [line 45, column 3]\n " shape="box"] +"capture#A#instance.d411336575e4bf632a1828f5f5979726_3" [label="3: Message Call: sHandler: \n n$3=*&self:A* [line 45, column 4]\n n$4=*n$3._b:B* [line 45, column 4]\n n$0=*&self:A* [line 45, column 16]\n n$5=_fun_B.sHandler:[objc_blockA.capture_1](n$0:A*,n$4:B*,(_fun_objc_blockA.capture_1,([by ref]n$0 &self:A*)):_fn_(*)) virtual [line 45, column 3]\n " shape="box"] "capture#A#instance.d411336575e4bf632a1828f5f5979726_3" -> "capture#A#instance.d411336575e4bf632a1828f5f5979726_2" ; diff --git a/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m.dot b/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m.dot index e864236d0..e32936ab2 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/specialized_method_with_block_params.m.dot @@ -88,7 +88,7 @@ digraph cfg { "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_3" -> "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_2" ; -"bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_4" [label="4: Call _fun_foo \n n$14=*&self:A* [line 40, column 7]\n n$16=*&self:A* [line 43, column 7]\n n$18=*&self:A* [line 46, column 7]\n n$19=_fun_foo[objc_blockA.bar2_3^objc_blockA.bar2_4](n$14:A*,n$18:A*) [line 39, column 3]\n " shape="box"] +"bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_4" [label="4: Call _fun_foo \n n$14=*&self:A* [line 40, column 7]\n n$16=*&self:A* [line 43, column 7]\n n$18=*&self:A* [line 46, column 7]\n n$19=_fun_foo[objc_blockA.bar2_3^objc_blockA.bar2_4](n$14:A*,(_fun_objc_blockA.bar2_4,([by ref]n$16 &self:A*)):_fn_(*),(_fun_objc_blockA.bar2_3,([by ref]n$14 &self:A*)):_fn_(*),n$18:A*) [line 39, column 3]\n " shape="box"] "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_4" -> "bar2#A#instance.413fa5106d6a23f2bf18df99659efb82_3" ; @@ -107,7 +107,7 @@ digraph cfg { "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_4" -> "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_3" ; -"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_5" [label="5: Call _fun_foo \n n$3=*&self:A* [line 27, column 7]\n n$4=*&x:int [line 27, column 7]\n n$7=*&self:A* [line 30, column 7]\n n$10=*&a:A* [line 33, column 7]\n n$11=_fun_foo[objc_blockA.bar:_1^objc_blockA.bar:_2](n$4:int,n$3:A*,n$10:A*) [line 26, column 3]\n " shape="box"] +"bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_5" [label="5: Call _fun_foo \n n$3=*&self:A* [line 27, column 7]\n n$4=*&x:int [line 27, column 7]\n n$7=*&self:A* [line 30, column 7]\n n$10=*&a:A* [line 33, column 7]\n n$11=_fun_foo[objc_blockA.bar:_1^objc_blockA.bar:_2](n$4:int,n$3:A*,(_fun_objc_blockA.bar:_2,([by ref]n$7 &self:A*)):_fn_(*),(_fun_objc_blockA.bar:_1,([by ref]n$3 &self:A*),([by ref]n$4 &x:int)):_fn_(*),n$10:A*) [line 26, column 3]\n " shape="box"] "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_5" -> "bar:#A(class A)#instance.3e4a860660eb436d473f8ceeb9c1a72b_4" ; @@ -126,11 +126,11 @@ digraph cfg { "call_foo_with_same_param#A#instance.7f01b1476c1662f7ce825ec7b1739a00_3" -> "call_foo_with_same_param#A#instance.7f01b1476c1662f7ce825ec7b1739a00_2" ; -"call_foo_with_same_param#A#instance.7f01b1476c1662f7ce825ec7b1739a00_4" [label="4: Call _fun_foo \n n$22=*&b:_fn_(*) [line 55, column 7]\n n$23=*&b:_fn_(*) [line 55, column 10]\n n$24=*&self:A* [line 55, column 13]\n n$25=_fun_foo[objc_blockA.call_foo_with_same_param_5^objc_blockA.call_foo_with_same_param_5](n$30:A*,n$24:A*) [line 55, column 3]\n " shape="box"] +"call_foo_with_same_param#A#instance.7f01b1476c1662f7ce825ec7b1739a00_4" [label="4: Call _fun_foo \n n$22=*&b:_fn_(*) [line 55, column 7]\n n$23=*&b:_fn_(*) [line 55, column 10]\n n$24=*&self:A* [line 55, column 13]\n n$25=_fun_foo[objc_blockA.call_foo_with_same_param_5^objc_blockA.call_foo_with_same_param_5](n$30:A*,(_fun_objc_blockA.call_foo_with_same_param_5,([by ref]n$30 &self:A*)):_fn_(*),(_fun_objc_blockA.call_foo_with_same_param_5,([by ref]n$30 &self:A*)):_fn_(*),n$24:A*) [line 55, column 3]\n " shape="box"] "call_foo_with_same_param#A#instance.7f01b1476c1662f7ce825ec7b1739a00_4" -> "call_foo_with_same_param#A#instance.7f01b1476c1662f7ce825ec7b1739a00_3" ; -"call_foo_with_same_param#A#instance.7f01b1476c1662f7ce825ec7b1739a00_5" [label="5: Call _fun_foo \n n$26=*&b:_fn_(*) [line 54, column 7]\n n$27=*&b:_fn_(*) [line 54, column 10]\n n$28=*&self:A* [line 54, column 13]\n n$29=_fun_foo[objc_blockA.call_foo_with_same_param_5^objc_blockA.call_foo_with_same_param_5](n$30:A*,n$28:A*) [line 54, column 3]\n " shape="box"] +"call_foo_with_same_param#A#instance.7f01b1476c1662f7ce825ec7b1739a00_5" [label="5: Call _fun_foo \n n$26=*&b:_fn_(*) [line 54, column 7]\n n$27=*&b:_fn_(*) [line 54, column 10]\n n$28=*&self:A* [line 54, column 13]\n n$29=_fun_foo[objc_blockA.call_foo_with_same_param_5^objc_blockA.call_foo_with_same_param_5](n$30:A*,(_fun_objc_blockA.call_foo_with_same_param_5,([by ref]n$30 &self:A*)):_fn_(*),(_fun_objc_blockA.call_foo_with_same_param_5,([by ref]n$30 &self:A*)):_fn_(*),n$28:A*) [line 54, column 3]\n " shape="box"] "call_foo_with_same_param#A#instance.7f01b1476c1662f7ce825ec7b1739a00_5" -> "call_foo_with_same_param#A#instance.7f01b1476c1662f7ce825ec7b1739a00_4" ; diff --git a/infer/tests/codetoanalyze/objc/shared/block/Blocks_as_parameters.m.dot b/infer/tests/codetoanalyze/objc/shared/block/Blocks_as_parameters.m.dot index 6a44c6d59..319ca6961 100644 --- a/infer/tests/codetoanalyze/objc/shared/block/Blocks_as_parameters.m.dot +++ b/infer/tests/codetoanalyze/objc/shared/block/Blocks_as_parameters.m.dot @@ -33,7 +33,7 @@ digraph cfg { "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_3" -> "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_2" ; -"f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_4" [label="4: Message Call: foo:and: \n n$4=*&self:B* [line 23, column 10]\n n$5=*n$4.h:int [line 23, column 10]\n n$2=*&self:B* const [line 24, column 11]\n n$6=_fun_B.foo:and:[objc_blockB.f_1](n$5:int,n$2:B* const ) [line 23, column 3]\n " shape="box"] +"f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_4" [label="4: Message Call: foo:and: \n n$4=*&self:B* [line 23, column 10]\n n$5=*n$4.h:int [line 23, column 10]\n n$2=*&self:B* const [line 24, column 11]\n n$6=_fun_B.foo:and:[objc_blockB.f_1](n$5:int,n$2:B* const ,(_fun_objc_blockB.f_1,([by ref]n$2 &self:B* const )):_fn_(*)) [line 23, column 3]\n " shape="box"] "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_4" -> "f#B#instance.f1371ff5e7f410d3df6a2e71ff0a814e_3" ; diff --git a/infer/tests/codetoanalyze/objc/shared/block/block-it.m.dot b/infer/tests/codetoanalyze/objc/shared/block/block-it.m.dot index 68f4d5733..3f6bc9e29 100644 --- a/infer/tests/codetoanalyze/objc/shared/block/block-it.m.dot +++ b/infer/tests/codetoanalyze/objc/shared/block/block-it.m.dot @@ -63,7 +63,7 @@ digraph cfg { "array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_2" [label="2: Exit MyBlock.array \n " color=yellow style=filled] -"array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_3" [label="3: Message Call: enumerateObjectsUsingBlock: \n n$5=*&a:NSArray* [line 19, column 4]\n n$6=_fun_NSArray.enumerateObjectsUsingBlock:[objc_blockMyBlock.array_1](n$5:NSArray*) virtual [line 19, column 3]\n " shape="box"] +"array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_3" [label="3: Message Call: enumerateObjectsUsingBlock: \n n$5=*&a:NSArray* [line 19, column 4]\n n$6=_fun_NSArray.enumerateObjectsUsingBlock:[objc_blockMyBlock.array_1](n$5:NSArray*,(_fun_objc_blockMyBlock.array_1):_fn_(*)) virtual [line 19, column 3]\n " shape="box"] "array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_3" -> "array#MyBlock#instance.8be6e5b5e968d186440e1931c9eb40de_2" ;