diff --git a/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.dot b/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.dot index e129d530c..a7c997894 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.dot +++ b/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.dot @@ -1,40 +1,65 @@ digraph iCFG { -10 [label="10: BinaryOperatorStmt: Assign \n *&#GB$g:int =7 [line 23]\n " shape="box"] +16 [label="16: BinaryOperatorStmt: Assign \n *&#GB$g:int =7 [line 23]\n " shape="box"] + + + 16 -> 15 ; +15 [label="15: DeclStmt \n *&z:int =3 [line 25]\n " shape="box"] + + + 15 -> 14 ; +14 [label="14: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block_My_manager_m______1); [line 26]\n n$7=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_My_manager_m______1 ):unsigned long ) [line 26]\n *&__objc_anonymous_block_My_manager_m______1:class __objc_anonymous_block_My_manager_m______1 =n$7 [line 26]\n n$8=*&z:int [line 26]\n *n$7.z:int =n$8 [line 26]\n n$5=*&z:int [line 26]\n *&b:_fn_ (*)=(_fun___objc_anonymous_block_My_manager_m______1,n$5) [line 26]\n REMOVE_TEMPS(n$7,n$8,n$5); [line 26]\n " shape="box"] + + + 14 -> 10 ; +13 [label="13: BinaryOperatorStmt: Assign \n n$6=*&z:int [line 27]\n *&#GB$g:int =(n$6 + 3) [line 27]\n REMOVE_TEMPS(n$6); [line 27]\n APPLY_ABSTRACTION; [line 27]\n " shape="box"] + + + 13 -> 12 ; +12 [label="12: Exit __objc_anonymous_block_My_manager_m______1 \n " color=yellow style=filled] + + +11 [label="11: Start __objc_anonymous_block_My_manager_m______1\nFormals: z:int \nLocals: \nCaptured: z:int \n DECLARE_LOCALS(&return); [line 26]\n " color=yellow style=filled] + + + 11 -> 13 ; +10 [label="10: Call n$4 \n n$4=*&b:_fn_ (*) [line 29]\n n$4() [line 29]\n REMOVE_TEMPS(n$4); [line 29]\n NULLIFY(&b,false); [line 29]\n " shape="box"] 10 -> 9 ; -9 [label="9: DeclStmt \n *&z:int =3 [line 25]\n " shape="box"] +9 [label="9: DeclStmt \n *&p:int *=0 [line 30]\n " shape="box"] - 9 -> 8 ; -8 [label="8: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block_My_manager_my_mehtod______1); [line 26]\n n$4=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block_My_manager_my_mehtod______1 ):unsigned long ) [line 26]\n *&__objc_anonymous_block_My_manager_my_mehtod______1:class __objc_anonymous_block_My_manager_my_mehtod______1 =n$4 [line 26]\n n$5=*&z:int [line 26]\n *n$4.z:int =n$5 [line 26]\n n$2=*&z:int [line 26]\n *&b:_fn_ (*)=(_fun___objc_anonymous_block_My_manager_my_mehtod______1,n$2) [line 26]\n REMOVE_TEMPS(n$4,n$5,n$2); [line 26]\n " shape="box"] + 9 -> 4 ; +8 [label="8: Return Stmt \n NULLIFY(&p,false); [line 32]\n n$3=*&z:int [line 32]\n *&return:int =n$3 [line 32]\n REMOVE_TEMPS(n$3); [line 32]\n NULLIFY(&__objc_anonymous_block_My_manager_m______1,true); [line 32]\n APPLY_ABSTRACTION; [line 32]\n " shape="box"] - 8 -> 4 ; -7 [label="7: BinaryOperatorStmt: Assign \n n$3=*&z:int [line 27]\n *&#GB$g:int =(n$3 + 3) [line 27]\n REMOVE_TEMPS(n$3); [line 27]\n APPLY_ABSTRACTION; [line 27]\n " shape="box"] + 8 -> 2 ; +7 [label="7: Return Stmt \n n$1=*&p:int * [line 31]\n n$2=*n$1:int [line 31]\n *&return:int =n$2 [line 31]\n REMOVE_TEMPS(n$1,n$2); [line 31]\n NULLIFY(&__objc_anonymous_block_My_manager_m______1,true); [line 31]\n NULLIFY(&p,false); [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="box"] - 7 -> 6 ; -6 [label="6: Exit __objc_anonymous_block_My_manager_my_mehtod______1 \n " color=yellow style=filled] + 7 -> 2 ; +6 [label="6: Prune (false branch) \n PRUNE(((n$0 == 6) == 0), false); [line 31]\n REMOVE_TEMPS(n$0); [line 31]\n " shape="invhouse"] -5 [label="5: Start __objc_anonymous_block_My_manager_my_mehtod______1\nFormals: z:int \nLocals: \nCaptured: z:int \n DECLARE_LOCALS(&return); [line 26]\n " color=yellow style=filled] + 6 -> 8 ; +5 [label="5: Prune (true branch) \n PRUNE(((n$0 == 6) != 0), true); [line 31]\n REMOVE_TEMPS(n$0); [line 31]\n " shape="invhouse"] 5 -> 7 ; -4 [label="4: Call n$1 \n n$1=*&b:_fn_ (*) [line 29]\n n$1() [line 29]\n REMOVE_TEMPS(n$1); [line 29]\n NULLIFY(&b,false); [line 29]\n " shape="box"] +4 [label="4: BinaryOperatorStmt: EQ \n n$0=*&#GB$g:int [line 31]\n " shape="box"] - 4 -> 3 ; -3 [label="3: Return Stmt \n n$0=*&z:int [line 30]\n *&return:int =n$0 [line 30]\n REMOVE_TEMPS(n$0); [line 30]\n NULLIFY(&__objc_anonymous_block_My_manager_my_mehtod______1,true); [line 30]\n APPLY_ABSTRACTION; [line 30]\n " shape="box"] + 4 -> 5 ; + 4 -> 6 ; +3 [label="3: + \n NULLIFY(&__objc_anonymous_block_My_manager_m______1,true); [line 31]\n NULLIFY(&b,false); [line 31]\n NULLIFY(&p,false); [line 31]\n NULLIFY(&self,false); [line 31]\n " ] 3 -> 2 ; -2 [label="2: Exit My_manager_my_mehtod \n " color=yellow style=filled] +2 [label="2: Exit My_manager_m \n " color=yellow style=filled] -1 [label="1: Start My_manager_my_mehtod\nFormals: self:class My_manager *\nLocals: z:int b:_fn_ (*) \n DECLARE_LOCALS(&return,&z,&b); [line 21]\n NULLIFY(&b,false); [line 21]\n NULLIFY(&self,false); [line 21]\n " color=yellow style=filled] +1 [label="1: Start My_manager_m\nFormals: self:class My_manager *\nLocals: p:int * z:int b:_fn_ (*) \n DECLARE_LOCALS(&return,&p,&z,&b); [line 21]\n NULLIFY(&b,false); [line 21]\n NULLIFY(&p,false); [line 21]\n NULLIFY(&self,false); [line 21]\n " color=yellow style=filled] - 1 -> 10 ; + 1 -> 16 ; } diff --git a/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.m b/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.m index 0c03b775d..eba0067d1 100644 --- a/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.m +++ b/infer/tests/codetoanalyze/objc/frontend/block/block_no_args.m @@ -12,24 +12,23 @@ int g; @interface My_manager :NSObject -- (int) my_mehtod; +- (int) m; @end @implementation My_manager -- (int) my_mehtod +- (int) m { - g=7; + g = 7; void (^b)(); - int z=3; - b=^( ){ - g=z+3; + int z = 3; + b = ^( ){ + g = z + 3; }; b(); - return z; + int *p = 0; + if (g == 6) return *p; + else return z; } - - - @end diff --git a/infer/tests/endtoend/objc/BlockGlobalVariableTest.java b/infer/tests/endtoend/objc/BlockGlobalVariableTest.java new file mode 100644 index 000000000..2c48c0e27 --- /dev/null +++ b/infer/tests/endtoend/objc/BlockGlobalVariableTest.java @@ -0,0 +1,63 @@ +/* +* Copyright (c) 2015 - 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. +*/ + +package endtoend.objc; + +import static org.hamcrest.MatcherAssert.assertThat; +import static utils.matchers.ResultContainsErrorInMethod.contains; +import static utils.matchers.ResultContainsExactly.containsExactly; + +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 BlockGlobalVariableTest { + + public static final String FILE = "infer/tests/codetoanalyze/objc/frontend/block/block_no_args.m"; + + private static ImmutableList inferCmd; + + public static final String NULL_DEREFERENCE = "NULL_DEREFERENCE"; + + @ClassRule + public static DebuggableTemporaryFolder folder = + new DebuggableTemporaryFolder(); + + @BeforeClass + public static void runInfer() throws InterruptedException, IOException { + inferCmd = InferRunner.createObjCInferCommand(folder, FILE); + } + + @Test + public void whenInferRunsOnMThenNPEIsFound() + throws InterruptedException, IOException, InferException { + InferResults inferResults = InferRunner.runInferObjC(inferCmd); + String[] procedures = { + "m", + }; + assertThat( + "Results should contain the expected null pointer exception", + inferResults, + containsExactly( + NULL_DEREFERENCE, + FILE, + procedures + ) + ); + } +}