diff --git a/infer/src/clang/cFrontend_config.ml b/infer/src/clang/cFrontend_config.ml index 44c6f5ea6..71270cb11 100644 --- a/infer/src/clang/cFrontend_config.ml +++ b/infer/src/clang/cFrontend_config.ml @@ -172,3 +172,5 @@ let block = "block" let atomic_att = "<\"Atomic\">" let infer_skip_gcc_ast_stmt = "__infer_skip_gcc_ast_stmt" + +let infer_skip_fun = "__infer_skip_function" diff --git a/infer/src/clang/cFrontend_config.mli b/infer/src/clang/cFrontend_config.mli index 91df893c2..1e29f8e3e 100644 --- a/infer/src/clang/cFrontend_config.mli +++ b/infer/src/clang/cFrontend_config.mli @@ -167,3 +167,5 @@ val block : string val atomic_att : string val infer_skip_gcc_ast_stmt : string + +val infer_skip_fun : string diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 265b56488..d6ca76776 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -2014,6 +2014,10 @@ struct "GCCAstStmt" stmt_info all_res_trans in { res_trans_to_parent with exps = res_trans_call.exps } + and cxxPseudoDestructorExpr_trans () = + let fun_name = Procname.from_string_c_fun CFrontend_config.infer_skip_fun in + { empty_res_trans with exps = [(Sil.Const (Sil.Cfun fun_name), Sil.Tvoid)] } + (* Translates a clang instruction into SIL instructions. It takes a *) (* a trans_state containing current info on the translation and it returns *) (* a result_state.*) @@ -2279,6 +2283,9 @@ struct | GCCAsmStmt (stmt_info, stmts) -> gccAstStmt_trans trans_state stmt_info stmts + | CXXPseudoDestructorExpr _ -> + cxxPseudoDestructorExpr_trans () + | s -> (Printing.log_stats "\n!!!!WARNING: found statement %s. \nACTION REQUIRED: Translation need to be defined. Statement ignored.... \n" (Ast_utils.string_of_stmt s); diff --git a/infer/tests/codetoanalyze/cpp/frontend/destructors/pseudo_destructor_expr.cpp b/infer/tests/codetoanalyze/cpp/frontend/destructors/pseudo_destructor_expr.cpp new file mode 100644 index 000000000..7f6c29248 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/destructors/pseudo_destructor_expr.cpp @@ -0,0 +1,26 @@ +/* + * 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. + */ + +typedef int T; +int f(int* p) { + int x = *p; + p->T::~T(); + return x; +} + +template +int destroy(T* ptr) { + ptr->T::~T(); + return 0; +} + +void test() { + int* t = 0; + destroy(&t); +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/destructors/pseudo_destructor_expr.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/destructors/pseudo_destructor_expr.cpp.dot new file mode 100644 index 000000000..34b6fa467 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/destructors/pseudo_destructor_expr.cpp.dot @@ -0,0 +1,51 @@ +digraph iCFG { +13 [label="13: DeclStmt \n *&t:int *=0 [line 24]\n " shape="box"] + + + 13 -> 12 ; +12 [label="12: Call _fun_destroy \n n$0=_fun_destroy(&t:int **) [line 25]\n REMOVE_TEMPS(n$0); [line 25]\n NULLIFY(&t,false); [line 25]\n APPLY_ABSTRACTION; [line 25]\n " shape="box"] + + + 12 -> 11 ; +11 [label="11: Exit test \n " color=yellow style=filled] + + +10 [label="10: Start test\nFormals: \nLocals: t:int * \n DECLARE_LOCALS(&return,&t); [line 23]\n " color=yellow style=filled] + + + 10 -> 13 ; +9 [label="9: Call _fun___infer_skip_function \n _fun___infer_skip_function() [line 19]\n " shape="box"] + + + 9 -> 8 ; +8 [label="8: Return Stmt \n *&return:int =0 [line 20]\n APPLY_ABSTRACTION; [line 20]\n " shape="box"] + + + 8 -> 7 ; +7 [label="7: Exit destroy \n " color=yellow style=filled] + + +6 [label="6: Start destroy\nFormals: ptr:int **\nLocals: \n DECLARE_LOCALS(&return); [line 18]\n NULLIFY(&ptr,false); [line 18]\n " color=yellow style=filled] + + + 6 -> 9 ; +5 [label="5: DeclStmt \n n$1=*&p:int * [line 12]\n n$2=*n$1:int [line 12]\n *&x:int =n$2 [line 12]\n REMOVE_TEMPS(n$1,n$2); [line 12]\n NULLIFY(&p,false); [line 12]\n " shape="box"] + + + 5 -> 4 ; +4 [label="4: Call _fun___infer_skip_function \n _fun___infer_skip_function() [line 13]\n " shape="box"] + + + 4 -> 3 ; +3 [label="3: Return Stmt \n n$0=*&x:int [line 14]\n *&return:int =n$0 [line 14]\n REMOVE_TEMPS(n$0); [line 14]\n NULLIFY(&x,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit f \n " color=yellow style=filled] + + +1 [label="1: Start f\nFormals: p:int *\nLocals: x:int \n DECLARE_LOCALS(&return,&x); [line 11]\n NULLIFY(&x,false); [line 11]\n " color=yellow style=filled] + + + 1 -> 5 ; +} diff --git a/infer/tests/frontend/cpp/DestructorsTest.java b/infer/tests/frontend/cpp/DestructorsTest.java index 96ed2f426..13409afaf 100644 --- a/infer/tests/frontend/cpp/DestructorsTest.java +++ b/infer/tests/frontend/cpp/DestructorsTest.java @@ -41,4 +41,9 @@ public class DestructorsTest { frontendTest("call_on_delete.cpp"); } + @Test + public void testCallOnPseudoDestructorExprDotFilesMatch() + throws InterruptedException, IOException, InferException { + frontendTest("pseudo_destructor_expr.cpp"); + } }