Model CHECK macro and fix the model for builtin_expect

Reviewed By: akotulski

Differential Revision: D3264368

fb-gh-sync-id: 1f79e19
fbshipit-source-id: 1f79e19
master
Dulma Churchill 9 years ago committed by Facebook Github Bot 8
parent a352c0ffa8
commit c3fbd5af29

@ -84,13 +84,7 @@ clock_t __infer_nondet_clock_t() {
return t; return t;
} }
long infer__builtin_expect(long e, long x) { long infer__builtin_expect(long e, long x) { return e; }
if (e == x) {
return x;
} else {
return e;
}
}
void* infer__builtin___memset_chk(void* dest, void* infer__builtin___memset_chk(void* dest,
int val, int val,

@ -151,6 +151,8 @@ let handleFailureInFunction = "handleFailureInFunction:file:lineNumber:descripti
let fbAssertWithSignalAndLogFunctionHelper = "FBAssertWithSignalAndLogFunctionHelper" let fbAssertWithSignalAndLogFunctionHelper = "FBAssertWithSignalAndLogFunctionHelper"
let google_LogMessageFatal = "google::LogMessageFatal_LogMessageFatal"
let pseudo_object_type = "<pseudo-object type>" let pseudo_object_type = "<pseudo-object type>"
let count = "count" let count = "count"

@ -143,6 +143,8 @@ val handleFailureInMethod : string
val handleFailureInFunction : string val handleFailureInFunction : string
val google_LogMessageFatal : string
val pseudo_object_type : string val pseudo_object_type : string
val count : string val count : string

@ -855,10 +855,7 @@ struct
res_trans_callee :: res_trans_p in res_trans_callee :: res_trans_p in
let sil_fe, is_cf_retain_release = CTrans_models.builtin_predefined_model fun_exp_stmt sil_fe in let sil_fe, is_cf_retain_release = CTrans_models.builtin_predefined_model fun_exp_stmt sil_fe in
if CTrans_models.is_assert_log sil_fe then if CTrans_models.is_assert_log sil_fe then
if Config.report_custom_error then CTrans_utils.trans_assertion sil_loc context trans_state.succ_nodes
CTrans_utils.trans_assertion_failure sil_loc context
else
CTrans_utils.trans_assume_false sil_loc context trans_state.succ_nodes
else else
let act_params = let act_params =
let params = IList.tl (collect_exprs result_trans_subexprs) in let params = IList.tl (collect_exprs result_trans_subexprs) in
@ -912,6 +909,9 @@ struct
let callee_pname = match sil_method with let callee_pname = match sil_method with
| Sil.Const (Sil.Cfun pn) -> pn | Sil.Const (Sil.Cfun pn) -> pn
| _ -> assert false (* method pointer not implemented, this shouldn't happen *) in | _ -> assert false (* method pointer not implemented, this shouldn't happen *) in
if CTrans_models.is_assert_log sil_method then
CTrans_utils.trans_assertion sil_loc context trans_state_pri.succ_nodes
else
(* As we may have nodes coming from different parameters we need to *) (* As we may have nodes coming from different parameters we need to *)
(* call instruction for each parameter and collect the results *) (* call instruction for each parameter and collect the results *)
(* afterwards. The 'instructions' function does not do that *) (* afterwards. The 'instructions' function does not do that *)
@ -1015,9 +1015,7 @@ struct
| _ -> None | _ -> None
(* assertions *) (* assertions *)
else if CTrans_models.is_handleFailureInMethod selector then else if CTrans_models.is_handleFailureInMethod selector then
if Config.report_custom_error then Some (CTrans_utils.trans_assertion sil_loc context trans_state.succ_nodes)
Some (CTrans_utils.trans_assertion_failure sil_loc context)
else Some (CTrans_utils.trans_assume_false sil_loc context trans_state.succ_nodes)
else None else None

@ -78,6 +78,9 @@ let is_assert_log_s funct =
funct = CFrontend_config.assert_fail || funct = CFrontend_config.assert_fail ||
funct = CFrontend_config.fbAssertWithSignalAndLogFunctionHelper funct = CFrontend_config.fbAssertWithSignalAndLogFunctionHelper
let is_assert_log_method m =
m = CFrontend_config.google_LogMessageFatal
let is_handleFailureInMethod funct = let is_handleFailureInMethod funct =
funct = CFrontend_config.handleFailureInMethod || funct = CFrontend_config.handleFailureInMethod ||
funct = CFrontend_config.handleFailureInFunction funct = CFrontend_config.handleFailureInFunction
@ -114,9 +117,11 @@ let builtin_predefined_model fun_stmt sil_fe =
(** If the function is a builtin model, return the model, otherwise return the function *) (** If the function is a builtin model, return the model, otherwise return the function *)
let is_assert_log sil_fe = let is_assert_log sil_fe =
match sil_fe with match sil_fe with
| Sil.Const (Sil.Cfun pn) when is_assert_log_s (Procname.to_string pn) -> true | Sil.Const (Sil.Cfun (Procname.ObjC_Cpp _ as pn)) -> is_assert_log_method (Procname.to_string pn)
| Sil.Const (Sil.Cfun (Procname.C _ as pn)) -> is_assert_log_s (Procname.to_string pn)
| _ -> false | _ -> false
let is_objc_memory_model_controlled o = let is_objc_memory_model_controlled o =
Core_foundation_model.is_objc_memory_model_controlled o Core_foundation_model.is_objc_memory_model_controlled o

@ -464,6 +464,11 @@ let trans_assume_false sil_loc context succ_nodes =
Cfg.Node.set_succs_exn context.CContext.cfg prune_node succ_nodes []; Cfg.Node.set_succs_exn context.CContext.cfg prune_node succ_nodes [];
{ empty_res_trans with root_nodes = [prune_node]; leaf_nodes = [prune_node] } { empty_res_trans with root_nodes = [prune_node]; leaf_nodes = [prune_node] }
let trans_assertion sil_loc context succ_nodes =
if Config.report_custom_error then
trans_assertion_failure sil_loc context
else trans_assume_false sil_loc context succ_nodes
let define_condition_side_effects e_cond instrs_cond sil_loc = let define_condition_side_effects e_cond instrs_cond sil_loc =
let (e', typ) = extract_exp_from_list e_cond "\nWARNING: Missing expression in IfStmt. Need to be fixed\n" in let (e', typ) = extract_exp_from_list e_cond "\nWARNING: Missing expression in IfStmt. Need to be fixed\n" in
match e' with match e' with

@ -85,9 +85,7 @@ val cast_operation :
trans_state -> Clang_ast_t.cast_kind -> (Sil.exp * Sil.typ) list -> Sil.typ -> Location.t -> trans_state -> Clang_ast_t.cast_kind -> (Sil.exp * Sil.typ) list -> Sil.typ -> Location.t ->
bool -> Ident.t list * Sil.instr list * (Sil.exp * Sil.typ) bool -> Ident.t list * Sil.instr list * (Sil.exp * Sil.typ)
val trans_assertion_failure : Location.t -> CContext.t -> trans_result val trans_assertion: Location.t -> CContext.t -> Cfg.Node.t list -> trans_result
val trans_assume_false : Location.t -> CContext.t -> Cfg.Node.t list -> trans_result
val is_owning_method : Clang_ast_t.stmt -> bool val is_owning_method : Clang_ast_t.stmt -> bool

@ -0,0 +1,18 @@
/*
* Copyright (c) 2016 - 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.
*/
#include <assert.h>
// We should report here no NPE, but also we should report div0 to show that we
// get the
// non-assertion branch.
int report_div0_and_no_npe(int* p) {
assert(p);
return *p / 0;
}

@ -0,0 +1,58 @@
/*
* Copyright (c) 2016 - 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.
*/
/*WARNING: This is not being tested in the endtoend tests because it requires
glog library.
Only to be run manually */
#include <glog/logging.h>
int log_fatal_example() {
int* p = nullptr;
if (p == nullptr) {
LOG(FATAL) << "this will crash\n";
}
return *p; // program should never get here
}
int check_example(int* a) {
CHECK(a);
return *a; // no null deref flagged by Infer
}
int log_non_fatal_example() {
int* a = nullptr;
LOG_IF(INFO, a) << "well\n";
LOG_IF(WARNING, a) << "well\n";
LOG_IF(ERROR, a) << "well\n";
return *a; // null deref flagged by Infer
}
int log_if_fatal_example() {
int* a = nullptr;
LOG_IF(FATAL, !a) << "well\n";
return *a; // no null deref
}
// Still not modelled
int check_ne_example(int x) {
CHECK_NE(x, 5);
return x;
}
int check_eq_example(int x, int y) {
CHECK_EQ(x, y);
return x;
}
int check_not_null_example(int* p) {
CHECK_NOTNULL(p);
return *p;
}

@ -0,0 +1,61 @@
/*
* 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.c;
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 AssertKeepBranchTest {
public static final String source_file = "assertions/assertion_example.c";
private static ImmutableList<String> inferCmd;
public static final String DIVIDE_BY_ZERO = "DIVIDE_BY_ZERO";
private static InferResults inferResults;
@BeforeClass
public static void runInfer() throws InterruptedException, IOException {
inferResults = InferResults.loadCInferResults(AssertKeepBranchTest.class, source_file);
}
@Test
public void whenRunsOnAssertionExampleThenDiv0AndNoNPEIsFound()
throws InterruptedException, IOException, InferException {
String[] methods = {
"report_div0_and_no_npe",
};
assertThat(
"Results should contain " + DIVIDE_BY_ZERO,
inferResults,
containsExactly(
DIVIDE_BY_ZERO,
source_file,
methods
)
);
}
}

@ -28,7 +28,7 @@ import utils.InferRunner;
public class AssertTest { public class AssertTest {
public static final String source_file = public static final String source_file =
"infer/tests/codetoanalyze/c/frontend/conditional_operator/assert_example.c"; "infer/tests/codetoanalyze/c/frontend/assertions/assert_example.c";
private static ImmutableList<String> inferCmd; private static ImmutableList<String> inferCmd;

@ -0,0 +1,41 @@
/*
* 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 frontend.c;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import java.io.IOException;
import utils.DebuggableTemporaryFolder;
import utils.InferException;
import utils.ClangFrontendUtils;
public class AssertionTest {
String conditionalOperatorBasePath = "infer/tests/codetoanalyze/c/frontend/assertions/";
@Rule
public DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder();
void frontendTest(String fileRelative) throws InterruptedException, IOException, InferException {
ClangFrontendUtils.createAndCompareCDotFiles(
folder,
conditionalOperatorBasePath + fileRelative);
}
@Ignore @Test
public void whenCaptureRunOnAssertExampleThenDotFilesAreTheSame()
throws InterruptedException, IOException, InferException {
frontendTest("assert_example.c");
}
}

@ -48,12 +48,6 @@ public class ConditionalOperatorTest {
frontendTest("cond2.c"); frontendTest("cond2.c");
} }
@Ignore @Test
public void whenCaptureRunOnAssertExampleThenDotFilesAreTheSame()
throws InterruptedException, IOException, InferException {
frontendTest("assert_example.c");
}
@Test @Test
public void whenCaptureRunOnIntNegationThenDotFilesAreTheSame() public void whenCaptureRunOnIntNegationThenDotFilesAreTheSame()
throws InterruptedException, IOException, InferException { throws InterruptedException, IOException, InferException {

Loading…
Cancel
Save