From 4feb93e91c585abc694e582f193d75bc49de28b4 Mon Sep 17 00:00:00 2001 From: Dino Distefano Date: Fri, 18 Dec 2015 03:59:33 -0800 Subject: [PATCH] Fixed FP for blocks used in loops generated by join operator Reviewed By: dulmarod Differential Revision: D2765074 fb-gh-sync-id: 5362f91 --- infer/src/backend/dom.ml | 16 ++-- infer/src/clang/ast_expressions.ml | 47 ++++++------ .../codetoanalyze/objc/errors/npe/blockenum.m | 66 +++++++++++++++++ infer/tests/endtoend/objc/NullParamTest.java | 73 +++++++++++++++++++ 4 files changed, 169 insertions(+), 33 deletions(-) create mode 100644 infer/tests/codetoanalyze/objc/errors/npe/blockenum.m create mode 100644 infer/tests/endtoend/objc/NullParamTest.java diff --git a/infer/src/backend/dom.ml b/infer/src/backend/dom.ml index 2918f1d80..f8b74f272 100644 --- a/infer/src/backend/dom.ml +++ b/infer/src/backend/dom.ml @@ -895,16 +895,12 @@ let ident_partial_meet (id1: Ident.t) (id2: Ident.t) = (** {2 Join and Meet for Exps} *) let const_partial_join c1 c2 = - if (Sil.const_equal c1 c2) then Sil.Const c1 - else match c1, c2 with - | Sil.Cfun _, Sil.Cfun _ - | Sil.Cstr _, Sil.Cstr _ - | Sil.Cclass _, Sil.Cclass _ - | Sil.Cattribute _, Sil.Cattribute _ -> - (L.d_strln "failure reason 18"; raise IList.Fail) - | _ -> - if (!Config.abs_val >= 2) then FreshVarExp.get_fresh_exp (Sil.Const c1) (Sil.Const c2) - else (L.d_strln "failure reason 19"; raise IList.Fail) + if Sil.const_equal c1 c2 then Sil.Const c1 + else if Sil.const_kind_equal c1 c2 then + (L.d_strln "failure reason 18"; raise IList.Fail) + else if !Config.abs_val >= 2 then + FreshVarExp.get_fresh_exp (Sil.Const c1) (Sil.Const c2) + else (L.d_strln "failure reason 19"; raise IList.Fail) let rec exp_partial_join (e1: Sil.exp) (e2: Sil.exp) : Sil.exp = (* L.d_str "exp_partial_join "; Sil.d_exp e1; L.d_str " "; Sil.d_exp e2; L.d_ln (); *) diff --git a/infer/src/clang/ast_expressions.ml b/infer/src/clang/ast_expressions.ml index c378ec77a..adc71cedb 100644 --- a/infer/src/clang/ast_expressions.ml +++ b/infer/src/clang/ast_expressions.ml @@ -374,28 +374,29 @@ let create_call stmt_info decl_pointer function_name tp parameters = let cast = create_implicit_cast_expr (fresh_stmt_info stmt_info) [decl_ref_exp] tp `FunctionToPointerDecay in Clang_ast_t.CallExpr (stmt_info, cast:: parameters, expr_info_call) -(* For a of type NSArray* Translate *) -(* [a enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL * stop) { *) -(* body_block *) -(* }; *) -(* ]; *) - -(* as follows: *) - -(* NSArray *objects = a; *) -(* void (^enumerateObjectsUsingBlock)(id, NSUInteger, BOOL* )= ^(id object, NSUInteger idx, BOOL* stop) { *) -(* body_block *) -(* }; *) -(* BOOL *stop = malloc(sizeof(BOOL)); *) -(* *stop = NO; *) - -(* for (NSUInteger idx=0; idx ei | _ -> assert false in - (* id object= objects[idx]; *) + (* id object = objects[idx]; *) let build_object_DeclStmt pobj decl_ref_expr_array decl_ref_expr_idx tp_idx = let open Clang_ast_t in match pobj with diff --git a/infer/tests/codetoanalyze/objc/errors/npe/blockenum.m b/infer/tests/codetoanalyze/objc/errors/npe/blockenum.m new file mode 100644 index 000000000..2277c41e0 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/errors/npe/blockenum.m @@ -0,0 +1,66 @@ +/* + * 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 + +@interface B : NSObject ++ foo:(id) obj; +@end + +@implementation B + ++ (B*) foo:(id) obj +{ + return obj; +} + +@end + + +@interface A : NSObject +- (NSMutableArray *) allResultsList: (NSArray *) allResults; +@end + + +@implementation A + +// From a diff +- (NSMutableArray *) allResultsList: (NSArray *) allResults { + NSMutableArray *resultsList = [[NSMutableArray alloc] init]; + [allResults enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + id *result = [B foo:obj]; + if (result != nil) { + [resultsList addObject:result]; + } + }]; + return resultsList; +} + +// How that code is translated in INFER +- (void) foo1: (NSArray*) a { + NSArray *objects = a; + NSMutableArray *resultsList = [[NSMutableArray alloc] init]; + void (^enumerateObjectsUsingBlock)(id, NSUInteger, BOOL* ) = + ^(id obj, NSUInteger idx, BOOL* stop) { + id *result = [B foo:obj]; + if (result != nil) { + [resultsList addObject:result]; + } + }; + BOOL *stop = malloc(sizeof(BOOL)); + *stop = NO; + for (NSUInteger idx = 0; idx < objects.count; idx++) { + id object = objects[idx]; + enumerateObjectsUsingBlock(object, idx, stop); + if ( *stop == YES) break; + } + free(stop); +} + +@end diff --git a/infer/tests/endtoend/objc/NullParamTest.java b/infer/tests/endtoend/objc/NullParamTest.java new file mode 100644 index 000000000..0ba718109 --- /dev/null +++ b/infer/tests/endtoend/objc/NullParamTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013 - 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.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 NullParamTest { + + public static final String block_file = + "infer/tests/codetoanalyze/objc/errors/npe/blockenum.m"; + + private static ImmutableList inferCmd; + + public static final String PARAMETER_NOT_NULL_CHECKED = "PARAMETER_NOT_NULL_CHECKED"; + + @ClassRule + public static DebuggableTemporaryFolder folder = + new DebuggableTemporaryFolder(); + + @BeforeClass + public static void runInfer() throws InterruptedException, IOException { + inferCmd = InferRunner.createObjCInferCommand( + folder, + block_file + ); + } + + @Test + public void whenInferRunsOnFoo1ParameterNilIsNotFound() + throws InterruptedException, IOException, InferException { + InferResults inferResults = InferRunner.runInferObjC(inferCmd); + assertThat( + "Results should not contain memory leak", + inferResults, + doesNotContain( + PARAMETER_NOT_NULL_CHECKED, + block_file, + "foo1:")); + } + @Test + public void whenInferRunsOnAllResultsListParameterNilIsNotFound() + throws InterruptedException, IOException, InferException { + InferResults inferResults = InferRunner.runInferObjC(inferCmd); + assertThat( + "Results should not contain memory leak", + inferResults, + doesNotContain( + PARAMETER_NOT_NULL_CHECKED, + block_file, + "allResultsList:")); + } +}