Fixing Bad pointer comparison checker in fast iteration

Reviewed By: dulmarod

Differential Revision: D2620791

fb-gh-sync-id: 3f892ba
master
Dino Distefano 9 years ago committed by facebook-github-bot-7
parent 03b4c11c06
commit 316ad95659

@ -366,7 +366,13 @@ let make_next_object_exp stmt_info item items =
let message_call = make_message_expr create_id_type let message_call = make_message_expr create_id_type
CFrontend_config.next_object items stmt_info false in CFrontend_config.next_object items stmt_info false in
let boi = { Clang_ast_t.boi_kind = `Assign } in let boi = { Clang_ast_t.boi_kind = `Assign } in
make_binary_stmt var_decl_ref message_call stmt_info (make_expr_info_with_objc_kind var_type `ObjCProperty) boi let expr_info = make_expr_info_with_objc_kind var_type `ObjCProperty in
let assignment = make_binary_stmt var_decl_ref message_call stmt_info expr_info boi in
let boi' = { Clang_ast_t.boi_kind = `NE } in
let cast = create_implicit_cast_expr stmt_info [var_decl_ref] var_type `LValueToRValue in
let nil_exp = create_nil stmt_info in
let loop_cond = make_binary_stmt cast nil_exp stmt_info expr_info boi' in
assignment, loop_cond
(* dispatch_once(v,block_def) is transformed as: *) (* dispatch_once(v,block_def) is transformed as: *)
(* void (^block_var)()=block_def; block_var() *) (* void (^block_var)()=block_def; block_var() *)

@ -68,7 +68,8 @@ val make_cast_expr : type_ptr -> decl_info -> decl_ref_expr_info -> object_kind
val make_self_field : string -> decl_info -> type_ptr -> named_decl_info -> stmt val make_self_field : string -> decl_info -> type_ptr -> named_decl_info -> stmt
val make_next_object_exp : stmt_info -> stmt -> Clang_ast_t.stmt -> Clang_ast_t.stmt val make_next_object_exp : stmt_info -> stmt -> Clang_ast_t.stmt ->
Clang_ast_t.stmt * Clang_ast_t.stmt
val create_nil : stmt_info -> stmt val create_nil : stmt_info -> stmt

@ -1354,13 +1354,23 @@ struct
let dowhile_kind = Loops.DoWhile (cond, body) in let dowhile_kind = Loops.DoWhile (cond, body) in
loop_instruction trans_state dowhile_kind stmt_info loop_instruction trans_state dowhile_kind stmt_info
(* Fast iteration for colection
for (type_it i in collection) { body }
is translate as
{
i = type_next_object();
while(i != nil) { body; i = type_next_object();}
}
*)
and objCForCollectionStmt_trans trans_state item items body stmt_info = and objCForCollectionStmt_trans trans_state item items body stmt_info =
let _ = instruction trans_state item in let _ = instruction trans_state item in
(* Here we do ast transformation, so we don't need the value of the translation of the *) (* Here we do ast transformation, so we don't need the value of the translation of the *)
(* variable item but we still need to add the variable to the locals *) (* variable item but we still need to add the variable to the locals *)
let bin_op = Ast_expressions.make_next_object_exp stmt_info item items in let assign_next_object, cond = Ast_expressions.make_next_object_exp stmt_info item items in
let while_kind = Loops.While (None, bin_op, body) in let body' = Clang_ast_t.CompoundStmt (stmt_info, [body; assign_next_object]) in
loop_instruction trans_state while_kind stmt_info let null_stmt = Clang_ast_t.NullStmt (stmt_info,[]) in
let loop = Clang_ast_t.WhileStmt (stmt_info, [null_stmt; cond; body']) in
instruction trans_state (Clang_ast_t.CompoundStmt (stmt_info, [assign_next_object; loop]))
(* Assumption: We expect precisely 2 stmt corresponding to the 2 operands. *) (* Assumption: We expect precisely 2 stmt corresponding to the 2 operands. *)
and compoundAssignOperator trans_state stmt_info binary_operator_info expr_info stmt_list = and compoundAssignOperator trans_state stmt_info binary_operator_info expr_info stmt_list =

@ -0,0 +1,57 @@
/*
* 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.
*/
#import <Foundation/NSArray.h>
void bad1() {
NSNumber *n2;
int i;
if (!n2) {
i = 0;
} else {
i = 1;
}
}
void bad2(NSArray *a, NSNumber *n) {
int i = 0;
for (; !n; ) {
i = n.intValue;
}
}
void bad3(NSArray *a, NSNumber *n) {
int i = 0;
while (!n) {
i = n.intValue;
}
}
void good1(NSArray *a) {
int i = 0;
for (NSNumber *n in a) {
i = n.intValue;
}
}
void good2 () {
NSNumber *n2;
int i;
if (n2 != nil) {
i = 1;
} else {
i = 0;
}
}

@ -1,25 +1,33 @@
digraph iCFG { digraph iCFG {
10 [label="10: DeclStmt \n n$8=_fun_NSString_stringWithUTF8String:(\"Mercedes-Benz\":char *) [line 18]\n n$9=_fun_NSString_stringWithUTF8String:(\"BMW\":char *) [line 18]\n n$10=_fun_NSString_stringWithUTF8String:(\"Porsche\":char *) [line 18]\n n$11=_fun_NSString_stringWithUTF8String:(\"Opel\":char *) [line 19]\n n$12=_fun_NSString_stringWithUTF8String:(\"Volkswagen\":char *) [line 19]\n n$13=_fun_NSString_stringWithUTF8String:(\"Audi\":char *) [line 19]\n n$7=_fun_NSArray_arrayWithObjects:count:(n$8:struct objc_object *,n$9:struct objc_object *,n$10:struct objc_object *,n$11:struct objc_object *,n$12:struct objc_object *,n$13:struct objc_object *,0:struct objc_object *) [line 18]\n *&germanCars:class NSArray *=n$7 [line 18]\n REMOVE_TEMPS(n$7,n$8,n$9,n$10,n$11,n$12,n$13); [line 18]\n " shape="box"] 12 [label="12: DeclStmt \n n$10=_fun_NSString_stringWithUTF8String:(\"Mercedes-Benz\":char *) [line 18]\n n$11=_fun_NSString_stringWithUTF8String:(\"BMW\":char *) [line 18]\n n$12=_fun_NSString_stringWithUTF8String:(\"Porsche\":char *) [line 18]\n n$13=_fun_NSString_stringWithUTF8String:(\"Opel\":char *) [line 19]\n n$14=_fun_NSString_stringWithUTF8String:(\"Volkswagen\":char *) [line 19]\n n$15=_fun_NSString_stringWithUTF8String:(\"Audi\":char *) [line 19]\n n$9=_fun_NSArray_arrayWithObjects:count:(n$10:struct objc_object *,n$11:struct objc_object *,n$12:struct objc_object *,n$13:struct objc_object *,n$14:struct objc_object *,n$15:struct objc_object *,0:struct objc_object *) [line 18]\n *&germanCars:class NSArray *=n$9 [line 18]\n REMOVE_TEMPS(n$9,n$10,n$11,n$12,n$13,n$14,n$15); [line 18]\n " shape="box"]
10 -> 9 ; 12 -> 11 ;
9 [label="9: BinaryOperatorStmt: Assign \n n$6=*&germanCars:class NSArray * [line 20]\n n$5=_fun_NSArray_objectAtIndexedSubscript:(n$6:class NSArray *,3:unsigned long ) virtual [line 20]\n *&s:class NSString *=n$5 [line 20]\n REMOVE_TEMPS(n$5,n$6); [line 20]\n NULLIFY(&s,false); [line 20]\n APPLY_ABSTRACTION; [line 20]\n " shape="box"] 11 [label="11: BinaryOperatorStmt: Assign \n n$8=*&germanCars:class NSArray * [line 20]\n n$7=_fun_NSArray_objectAtIndexedSubscript:(n$8:class NSArray *,3:unsigned long ) virtual [line 20]\n *&s:class NSString *=n$7 [line 20]\n REMOVE_TEMPS(n$7,n$8); [line 20]\n NULLIFY(&s,false); [line 20]\n " shape="box"]
9 -> 4 ; 11 -> 10 ;
8 [label="8: Call _fun_NSLog \n n$3=_fun_NSString_stringWithUTF8String:(\"%@\":char *) [line 23]\n n$4=*&item:class NSString * [line 23]\n _fun_NSLog(n$3:struct objc_object *,n$4:class NSString *) [line 23]\n REMOVE_TEMPS(n$3,n$4); [line 23]\n NULLIFY(&item,false); [line 23]\n APPLY_ABSTRACTION; [line 23]\n " shape="box"] 10 [label="10: BinaryOperatorStmt: Assign \n n$6=*&germanCars:class NSArray * [line 22]\n n$5=_fun_NSArray_nextObject(n$6:class NSArray *) virtual [line 22]\n *&item:class NSString *=n$5 [line 22]\n REMOVE_TEMPS(n$5,n$6); [line 22]\n APPLY_ABSTRACTION; [line 22]\n " shape="box"]
10 -> 4 ;
9 [label="9: Call _fun_NSLog \n n$3=_fun_NSString_stringWithUTF8String:(\"%@\":char *) [line 23]\n n$4=*&item:class NSString * [line 23]\n _fun_NSLog(n$3:struct objc_object *,n$4:class NSString *) [line 23]\n REMOVE_TEMPS(n$3,n$4); [line 23]\n NULLIFY(&item,false); [line 23]\n " shape="box"]
9 -> 8 ;
8 [label="8: BinaryOperatorStmt: Assign \n n$2=*&germanCars:class NSArray * [line 22]\n n$1=_fun_NSArray_nextObject(n$2:class NSArray *) virtual [line 22]\n *&item:class NSString *=n$1 [line 22]\n REMOVE_TEMPS(n$1,n$2); [line 22]\n APPLY_ABSTRACTION; [line 22]\n " shape="box"]
8 -> 4 ; 8 -> 4 ;
7 [label="7: Prune (false branch) \n PRUNE((n$2 == 0), false); [line 22]\n REMOVE_TEMPS(n$0,n$1,n$2); [line 22]\n " shape="invhouse"] 7 [label="7: Prune (false branch) \n PRUNE(((n$0 != 0) == 0), false); [line 22]\n REMOVE_TEMPS(n$0); [line 22]\n " shape="invhouse"]
7 -> 3 ; 7 -> 3 ;
6 [label="6: Prune (true branch) \n PRUNE((n$2 != 0), true); [line 22]\n REMOVE_TEMPS(n$0,n$1,n$2); [line 22]\n " shape="invhouse"] 6 [label="6: Prune (true branch) \n PRUNE(((n$0 != 0) != 0), true); [line 22]\n REMOVE_TEMPS(n$0); [line 22]\n " shape="invhouse"]
6 -> 8 ; 6 -> 9 ;
5 [label="5: BinaryOperatorStmt: Assign \n n$1=*&germanCars:class NSArray * [line 22]\n n$0=_fun_NSArray_nextObject(n$1:class NSArray *) virtual [line 22]\n *&item:class NSString *=n$0 [line 22]\n n$2=*&item:class NSString * [line 22]\n " shape="box"] 5 [label="5: BinaryOperatorStmt: NE \n n$0=*&item:class NSString * [line 22]\n " shape="box"]
5 -> 6 ; 5 -> 6 ;
@ -38,5 +46,5 @@ digraph iCFG {
1 [label="1: Start main\nFormals: \nLocals: item:class NSString * germanCars:class NSArray * s:class NSString * \n DECLARE_LOCALS(&return,&item,&germanCars,&s); [line 14]\n NULLIFY(&germanCars,false); [line 14]\n NULLIFY(&item,false); [line 14]\n NULLIFY(&s,false); [line 14]\n " color=yellow style=filled] 1 [label="1: Start main\nFormals: \nLocals: item:class NSString * germanCars:class NSArray * s:class NSString * \n DECLARE_LOCALS(&return,&item,&germanCars,&s); [line 14]\n NULLIFY(&germanCars,false); [line 14]\n NULLIFY(&item,false); [line 14]\n NULLIFY(&s,false); [line 14]\n " color=yellow style=filled]
1 -> 10 ; 1 -> 12 ;
} }

@ -1,61 +1,69 @@
digraph iCFG { digraph iCFG {
19 [label="19: DeclStmt \n *&size:int =0 [line 26]\n " shape="box"] 21 [label="21: DeclStmt \n *&size:int =0 [line 26]\n " shape="box"]
19 -> 18 ; 21 -> 20 ;
18 [label="18: DeclStmt \n *&item:class NSArray *=0 [line 27]\n NULLIFY(&item,false); [line 27]\n APPLY_ABSTRACTION; [line 27]\n " shape="box"] 20 [label="20: DeclStmt \n *&item:class NSArray *=0 [line 27]\n NULLIFY(&item,false); [line 27]\n APPLY_ABSTRACTION; [line 27]\n " shape="box"]
18 -> 13 ; 20 -> 15 ;
17 [label="17: ComppoundAssignStmt \n n$12=*&item:class NSArray * [line 29]\n n$11=_fun_NSArray_count(n$12:class NSArray *) virtual [line 29]\n n$13=*&size:int [line 29]\n *&size:int =(n$13 + n$11) [line 29]\n REMOVE_TEMPS(n$11,n$12,n$13); [line 29]\n NULLIFY(&item,false); [line 29]\n APPLY_ABSTRACTION; [line 29]\n " shape="box"] 19 [label="19: ComppoundAssignStmt \n n$14=*&item:class NSArray * [line 29]\n n$13=_fun_NSArray_count(n$14:class NSArray *) virtual [line 29]\n n$15=*&size:int [line 29]\n *&size:int =(n$15 + n$13) [line 29]\n REMOVE_TEMPS(n$13,n$14,n$15); [line 29]\n NULLIFY(&item,false); [line 29]\n APPLY_ABSTRACTION; [line 29]\n " shape="box"]
17 -> 13 ; 19 -> 15 ;
16 [label="16: Prune (false branch) \n PRUNE((n$10 == 0), false); [line 28]\n REMOVE_TEMPS(n$8,n$9,n$10); [line 28]\n " shape="invhouse"] 18 [label="18: Prune (false branch) \n PRUNE((n$12 == 0), false); [line 28]\n REMOVE_TEMPS(n$10,n$11,n$12); [line 28]\n " shape="invhouse"]
16 -> 12 ; 18 -> 14 ;
15 [label="15: Prune (true branch) \n PRUNE((n$10 != 0), true); [line 28]\n REMOVE_TEMPS(n$8,n$9,n$10); [line 28]\n " shape="invhouse"] 17 [label="17: Prune (true branch) \n PRUNE((n$12 != 0), true); [line 28]\n REMOVE_TEMPS(n$10,n$11,n$12); [line 28]\n " shape="invhouse"]
15 -> 17 ; 17 -> 19 ;
14 [label="14: BinaryOperatorStmt: Assign \n n$9=*&items:class NSArray * [line 28]\n n$8=_fun_NSArray_nextObject(n$9:class NSArray *) virtual [line 28]\n *&item:class NSArray *=n$8 [line 28]\n n$10=*&item:class NSArray * [line 28]\n " shape="box"] 16 [label="16: BinaryOperatorStmt: Assign \n n$11=*&items:class NSArray * [line 28]\n n$10=_fun_NSArray_nextObject(n$11:class NSArray *) virtual [line 28]\n *&item:class NSArray *=n$10 [line 28]\n n$12=*&item:class NSArray * [line 28]\n " shape="box"]
14 -> 15 ; 16 -> 17 ;
14 -> 16 ; 16 -> 18 ;
13 [label="13: + \n " ] 15 [label="15: + \n " ]
13 -> 14 ; 15 -> 16 ;
12 [label="12: Return Stmt \n NULLIFY(&item,false); [line 31]\n NULLIFY(&items,false); [line 31]\n n$7=*&size:int [line 31]\n *&return:int =n$7 [line 31]\n REMOVE_TEMPS(n$7); [line 31]\n NULLIFY(&size,false); [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="box"] 14 [label="14: Return Stmt \n NULLIFY(&item,false); [line 31]\n NULLIFY(&items,false); [line 31]\n n$9=*&size:int [line 31]\n *&return:int =n$9 [line 31]\n REMOVE_TEMPS(n$9); [line 31]\n NULLIFY(&size,false); [line 31]\n APPLY_ABSTRACTION; [line 31]\n " shape="box"]
12 -> 11 ; 14 -> 13 ;
11 [label="11: Exit A_while_loop: \n " color=yellow style=filled] 13 [label="13: Exit A_while_loop: \n " color=yellow style=filled]
10 [label="10: Start A_while_loop:\nFormals: self:class A * items:class NSArray *\nLocals: item:class NSArray * size:int \n DECLARE_LOCALS(&return,&item,&size); [line 25]\n NULLIFY(&item,false); [line 25]\n NULLIFY(&self,false); [line 25]\n NULLIFY(&size,false); [line 25]\n " color=yellow style=filled] 12 [label="12: Start A_while_loop:\nFormals: self:class A * items:class NSArray *\nLocals: item:class NSArray * size:int \n DECLARE_LOCALS(&return,&item,&size); [line 25]\n NULLIFY(&item,false); [line 25]\n NULLIFY(&self,false); [line 25]\n NULLIFY(&size,false); [line 25]\n " color=yellow style=filled]
10 -> 19 ; 12 -> 21 ;
9 [label="9: DeclStmt \n *&size:int =0 [line 18]\n APPLY_ABSTRACTION; [line 18]\n " shape="box"] 11 [label="11: DeclStmt \n *&size:int =0 [line 18]\n " shape="box"]
9 -> 4 ; 11 -> 10 ;
8 [label="8: ComppoundAssignStmt \n n$5=*&item:class NSArray * [line 20]\n n$4=_fun_NSArray_count(n$5:class NSArray *) virtual [line 20]\n n$6=*&size:int [line 20]\n *&size:int =(n$6 + n$4) [line 20]\n REMOVE_TEMPS(n$4,n$5,n$6); [line 20]\n NULLIFY(&item,false); [line 20]\n APPLY_ABSTRACTION; [line 20]\n " shape="box"] 10 [label="10: BinaryOperatorStmt: Assign \n n$8=*&items:class NSArray * [line 19]\n n$7=_fun_NSArray_nextObject(n$8:class NSArray *) virtual [line 19]\n *&item:class NSArray *=n$7 [line 19]\n REMOVE_TEMPS(n$7,n$8); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"]
10 -> 4 ;
9 [label="9: ComppoundAssignStmt \n n$5=*&item:class NSArray * [line 20]\n n$4=_fun_NSArray_count(n$5:class NSArray *) virtual [line 20]\n n$6=*&size:int [line 20]\n *&size:int =(n$6 + n$4) [line 20]\n REMOVE_TEMPS(n$4,n$5,n$6); [line 20]\n NULLIFY(&item,false); [line 20]\n " shape="box"]
9 -> 8 ;
8 [label="8: BinaryOperatorStmt: Assign \n n$3=*&items:class NSArray * [line 19]\n n$2=_fun_NSArray_nextObject(n$3:class NSArray *) virtual [line 19]\n *&item:class NSArray *=n$2 [line 19]\n REMOVE_TEMPS(n$2,n$3); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"]
8 -> 4 ; 8 -> 4 ;
7 [label="7: Prune (false branch) \n PRUNE((n$3 == 0), false); [line 19]\n REMOVE_TEMPS(n$1,n$2,n$3); [line 19]\n " shape="invhouse"] 7 [label="7: Prune (false branch) \n PRUNE(((n$1 != 0) == 0), false); [line 19]\n REMOVE_TEMPS(n$1); [line 19]\n " shape="invhouse"]
7 -> 3 ; 7 -> 3 ;
6 [label="6: Prune (true branch) \n PRUNE((n$3 != 0), true); [line 19]\n REMOVE_TEMPS(n$1,n$2,n$3); [line 19]\n " shape="invhouse"] 6 [label="6: Prune (true branch) \n PRUNE(((n$1 != 0) != 0), true); [line 19]\n REMOVE_TEMPS(n$1); [line 19]\n " shape="invhouse"]
6 -> 8 ; 6 -> 9 ;
5 [label="5: BinaryOperatorStmt: Assign \n n$2=*&items:class NSArray * [line 19]\n n$1=_fun_NSArray_nextObject(n$2:class NSArray *) virtual [line 19]\n *&item:class NSArray *=n$1 [line 19]\n n$3=*&item:class NSArray * [line 19]\n " shape="box"] 5 [label="5: BinaryOperatorStmt: NE \n n$1=*&item:class NSArray * [line 19]\n " shape="box"]
5 -> 6 ; 5 -> 6 ;
@ -74,5 +82,5 @@ digraph iCFG {
1 [label="1: Start A_fast_loop:\nFormals: self:class A * items:class NSArray *\nLocals: item:class NSArray * size:int \n DECLARE_LOCALS(&return,&item,&size); [line 17]\n NULLIFY(&item,false); [line 17]\n NULLIFY(&self,false); [line 17]\n NULLIFY(&size,false); [line 17]\n " color=yellow style=filled] 1 [label="1: Start A_fast_loop:\nFormals: self:class A * items:class NSArray *\nLocals: item:class NSArray * size:int \n DECLARE_LOCALS(&return,&item,&size); [line 17]\n NULLIFY(&item,false); [line 17]\n NULLIFY(&self,false); [line 17]\n NULLIFY(&size,false); [line 17]\n " color=yellow style=filled]
1 -> 9 ; 1 -> 11 ;
} }

@ -0,0 +1,67 @@
/*
* 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.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 NSNumber2Test {
public static final String NSNUMBER_FILE =
"infer/tests/codetoanalyze/objc/errors/bad_ptr_comparisons/badpointer.m";
private static ImmutableList<String> inferCmd;
public static final String BAD_POINTER_COMPARISON = "BAD_POINTER_COMPARISON";
@ClassRule
public static DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder();
@BeforeClass
public static void runInfer() throws InterruptedException, IOException {
inferCmd = InferRunner.createObjCInferCommand(
folder,
NSNUMBER_FILE);
}
@Test
public void badNSNumberPointerComparisonShouldBeFound()
throws InterruptedException, IOException, InferException {
InferResults inferResults = InferRunner.runInferObjC(inferCmd);
String[] methods = {
"bad1",
"bad2",
"bad3"
};
assertThat(
"Results should contain " + BAD_POINTER_COMPARISON,
inferResults,
containsExactly(
BAD_POINTER_COMPARISON,
NSNUMBER_FILE,
methods
)
);
}
}
Loading…
Cancel
Save