From bfe10e382994054255786d40cb500570dfcb4695 Mon Sep 17 00:00:00 2001 From: Andrzej Kotulski Date: Fri, 16 Oct 2015 06:09:37 -0700 Subject: [PATCH] Fix handling of C++ references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: @​public This diff changes following things: 1. expression_info.type_ptr has type than decl_ref_info.type_ptr for reference types. Use type from decl_ref_info as a source of truth 2. reference types need to have one extra dereference that is not in AST. Add handling for this. 3. [small refactor] create function that creates temporary variable from res_trans expression and returns new res_trans. Some caveats: 1. types are not quite right yet (see .dot files). 2. decl_ref_info might not be set for DeclRefExpr, make frontend crash in that case to catch when this happens This is high risk change since it changes behavior of every translation on very widely used expr. Reviewed By: @dulmarod Differential Revision: D2540632 fb-gh-sync-id: aa28936 --- infer/src/clang/cTrans.ml | 16 +- infer/src/clang/cTrans_utils.ml | 29 +- infer/src/clang/cTrans_utils.mli | 6 + infer/src/clang/cTypes.ml | 5 + infer/src/clang/cTypes.mli | 2 + .../cpp/frontend/reference/box.cpp | 14 + .../cpp/frontend/reference/box.cpp.dot | 21 + .../cpp/frontend/reference/init.cpp | 26 + .../cpp/frontend/reference/init.cpp.dot | 59 +++ .../cpp/frontend/reference/member_access.cpp | 23 + .../frontend/reference/member_access.cpp.dot | 43 ++ .../reference/member_access_from_return.cpp | 27 ++ .../member_access_from_return.cpp.dot | 65 +++ .../reference/reference_struct_e2e.cpp | 139 ++++++ .../reference/reference_struct_e2e.cpp.dot | 447 ++++++++++++++++++ .../frontend/reference/reference_type_e2e.cpp | 51 ++ .../reference/reference_type_e2e.cpp.dot | 154 ++++++ .../cpp/frontend/reference/unbox.cpp | 34 ++ .../cpp/frontend/reference/unbox.cpp.dot | 89 ++++ .../endtoend/cpp/ReferenceStructTest.java | 70 +++ .../tests/endtoend/cpp/ReferenceTypeTest.java | 68 +++ infer/tests/frontend/cpp/ReferenceTest.java | 73 +++ 22 files changed, 1451 insertions(+), 10 deletions(-) create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/box.cpp create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/box.cpp.dot create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/init.cpp create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/init.cpp.dot create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/member_access.cpp create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/member_access.cpp.dot create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/member_access_from_return.cpp create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/member_access_from_return.cpp.dot create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/reference_struct_e2e.cpp create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/reference_struct_e2e.cpp.dot create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/reference_type_e2e.cpp create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/reference_type_e2e.cpp.dot create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/unbox.cpp create mode 100644 infer/tests/codetoanalyze/cpp/frontend/reference/unbox.cpp.dot create mode 100644 infer/tests/endtoend/cpp/ReferenceStructTest.java create mode 100644 infer/tests/endtoend/cpp/ReferenceTypeTest.java create mode 100644 infer/tests/frontend/cpp/ReferenceTest.java diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index f8c9d9dc9..a29356220 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -296,7 +296,9 @@ struct Printing.log_out " priority node free = '%s'\n@." (string_of_bool (PriorityNode.is_priority_free trans_state)); let context = trans_state.context in - let tp = expr_info.Clang_ast_t.ei_type_ptr in + let pln = trans_state.parent_line_number in + let sil_loc = CLocation.get_sil_location stmt_info pln context in + let tp = get_type_decl_ref_exp_info decl_ref_expr_info in let typ = CTypes_decl.type_ptr_to_sil_type context.tenv tp in let name = get_name_decl_ref_exp_info decl_ref_expr_info stmt_info in let procname = Cfg.Procdesc.get_proc_name context.procdesc in @@ -355,7 +357,11 @@ struct [(e, typ)] else [(e, typ)] in Printing.log_out "\n\n PVAR ='%s'\n\n" (Sil.pvar_to_string pvar); - { empty_res_trans with exps = exps } + let res_trans = { empty_res_trans with exps = exps } in + if CTypes.is_reference_type tp then + (* dereference pvar due to the behavior of reference types in clang's AST *) + dereference_value_from_result sil_loc res_trans + else res_trans | _ -> let print_error decl_kind = Printing.log_stats @@ -366,7 +372,6 @@ struct | `CXXMethod -> print_error decl_kind; assert false | _ -> print_error decl_kind; assert false - let cxxThisExpr_trans trans_state stmt_info expr_info = let context = trans_state.context in let pln = trans_state.parent_line_number in @@ -379,10 +384,7 @@ struct let typ = CTypes_decl.type_ptr_to_sil_type context.CContext.tenv tp in let exps = [(exp, typ)] in (* there is no cast operation in AST, but backend needs it *) - let cast_kind = `LValueToRValue in - let cast_ids, cast_inst, cast_exp = cast_operation context cast_kind exps - (* unused *) typ sil_loc (* is_objc_bridged *) false in - { empty_res_trans with ids = cast_ids; instrs = cast_inst; exps = [(cast_exp, typ)] } + dereference_value_from_result sil_loc { empty_res_trans with exps = exps } let rec labelStmt_trans trans_state stmt_info stmt_list label_name = (* go ahead with the translation *) diff --git a/infer/src/clang/cTrans_utils.ml b/infer/src/clang/cTrans_utils.ml index 00af5f767..2603c41c8 100644 --- a/infer/src/clang/cTrans_utils.ml +++ b/infer/src/clang/cTrans_utils.ml @@ -358,6 +358,24 @@ let builtin_trans trans_state loc stmt_info function_type callee_pname_opt = Some (alloc_trans trans_state loc stmt_info function_type false) else None +let dereference_var_sil (exp, typ) sil_loc = + let id = Ident.create_fresh Ident.knormal in + let sil_instr = Sil.Letderef (id, exp, typ, sil_loc) in + ([id], [sil_instr], Sil.Var id) + +(** Given trans_result with ONE expression, create temporary variable with *) +(** value of an expression assigned to it *) +let dereference_value_from_result sil_loc trans_result = + let (obj_sil, class_typ) = extract_exp_from_list trans_result.exps "" in + let cast_ids, cast_inst, cast_exp = dereference_var_sil (obj_sil, class_typ) sil_loc in + let typ_no_ptr = match class_typ with | Sil.Tptr (typ, _) -> typ | _ -> assert false in + { trans_result with + ids = trans_result.ids @ cast_ids; + instrs = trans_result.instrs @ cast_inst; + exps = [(cast_exp, typ_no_ptr)] + } + + let cast_operation context cast_kind exps cast_typ sil_loc is_objc_bridged = let (exp, typ) = extract_exp_from_list exps "" in if is_objc_bridged then @@ -373,9 +391,7 @@ let cast_operation context cast_kind exps cast_typ sil_loc is_objc_bridged = | `LValueToRValue -> (* Takes an LValue and allow it to use it as RValue. *) (* So we assign the LValue to a temp and we pass it to the parent.*) - let id = Ident.create_fresh Ident.knormal in - let sil_instr = [Sil.Letderef (id, exp, typ, sil_loc)] in - ([id], sil_instr, Sil.Var id) + dereference_var_sil (exp, typ) sil_loc | `CPointerToObjCPointerCast -> ([], [], Sil.Cast(typ, exp)) | _ -> @@ -451,6 +467,13 @@ let get_name_decl_ref_exp_info decl_ref_expr_info si = (Clang_ast_j.string_of_decl_ref_expr_info decl_ref_expr_info ) (Clang_ast_j.string_of_stmt_info si); assert false +let get_type_decl_ref_exp_info decl_ref_expr_info = + match decl_ref_expr_info.Clang_ast_t.drti_decl_ref with + | Some d -> (match d.Clang_ast_t.dr_type_ptr with + | Some ptr -> ptr + | _ -> assert false) + | _ -> assert false + let is_superinstance mei = match mei.Clang_ast_t.omei_receiver_kind with | `SuperInstance -> true diff --git a/infer/src/clang/cTrans_utils.mli b/infer/src/clang/cTrans_utils.mli index d8c5fe2cf..1c95e96bd 100644 --- a/infer/src/clang/cTrans_utils.mli +++ b/infer/src/clang/cTrans_utils.mli @@ -71,6 +71,8 @@ val compute_instr_ids_exp_to_parent : val get_name_decl_ref_exp_info : Clang_ast_t.decl_ref_expr_info -> Clang_ast_t.stmt_info -> string +val get_type_decl_ref_exp_info : Clang_ast_t.decl_ref_expr_info -> Clang_ast_t.type_ptr + val get_decl_kind : Clang_ast_t.decl_ref_expr_info -> Clang_ast_t.decl_kind val get_decl_pointer : Clang_ast_t.decl_ref_expr_info -> Clang_ast_t.pointer @@ -81,6 +83,10 @@ val is_member_exp : Clang_ast_t.stmt -> bool val get_type_from_exp_stmt : Clang_ast_t.stmt -> Clang_ast_t.type_ptr +(** Given trans_result with ONE expression, create temporary variable with *) +(** dereferenced value of an expression assigned to it *) +val dereference_value_from_result : Location.t -> trans_result -> trans_result + val cast_operation : CContext.t -> Clang_ast_t.cast_kind -> (Sil.exp * Sil.typ) list -> Sil.typ -> Location.t -> bool -> Ident.t list * Sil.instr list * Sil.exp diff --git a/infer/src/clang/cTypes.ml b/infer/src/clang/cTypes.ml index 4f3df9d7b..63b8382d3 100644 --- a/infer/src/clang/cTypes.ml +++ b/infer/src/clang/cTypes.ml @@ -104,6 +104,11 @@ let is_block_type tp = | Some BlockPointerType _ -> true | _ -> false +let is_reference_type tp = + match Ast_utils.get_desugared_type tp with + | Some Clang_ast_t.LValueReferenceType _ -> true + | _ -> false + (* Expand a named type Tvar if it has a definition in tenv. This is used for Tenum, Tstruct, etc. *) let rec expand_structured_type tenv typ = match typ with diff --git a/infer/src/clang/cTypes.mli b/infer/src/clang/cTypes.mli index 85b06ea9f..d78bb2ca2 100644 --- a/infer/src/clang/cTypes.mli +++ b/infer/src/clang/cTypes.mli @@ -31,6 +31,8 @@ val return_type_of_function_type : Clang_ast_t.type_ptr -> Clang_ast_t.type_ptr val is_block_type : Clang_ast_t.type_ptr -> bool +val is_reference_type : Clang_ast_t.type_ptr -> bool + val expand_structured_type : Sil.tenv -> Sil.typ -> Sil.typ val get_name_from_type_pointer : string -> string * string diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/box.cpp b/infer/tests/codetoanalyze/cpp/frontend/reference/box.cpp new file mode 100644 index 000000000..001e9cc6a --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/box.cpp @@ -0,0 +1,14 @@ +/* +* 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. +*/ + +void test() { + int v = 3; + int& r = v; + int* p = &v; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/box.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/reference/box.cpp.dot new file mode 100644 index 000000000..d11258665 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/box.cpp.dot @@ -0,0 +1,21 @@ +digraph iCFG { +5 [label="5: DeclStmt \n *&v:int =3 [line 11]\n " shape="box"] + + + 5 -> 4 ; +4 [label="4: DeclStmt \n *&r:int =&v [line 12]\n NULLIFY(&r,false); [line 12]\n " shape="box"] + + + 4 -> 3 ; +3 [label="3: DeclStmt \n *&p:int *=&v [line 13]\n NULLIFY(&p,false); [line 13]\n NULLIFY(&v,false); [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit test \n " color=yellow style=filled] + + +1 [label="1: Start test\nFormals: \nLocals: p:int * r:int & v:int \n DECLARE_LOCALS(&return,&p,&r,&v); [line 10]\n NULLIFY(&p,false); [line 10]\n NULLIFY(&r,false); [line 10]\n " color=yellow style=filled] + + + 1 -> 5 ; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/init.cpp b/infer/tests/codetoanalyze/cpp/frontend/reference/init.cpp new file mode 100644 index 000000000..352adf05b --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/init.cpp @@ -0,0 +1,26 @@ +/* +* 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. +*/ + +void init_from_ref(int &par) { + int v = par; + int& d = par; + int* p = ∥ +} + +void init_from_val(int par) { + int v = par; + int& d = par; + int* p = ∥ +} + +void init_from_ptr(int *par) { + int v = *par; + int& d = *par; + int* p = par; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/init.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/reference/init.cpp.dot new file mode 100644 index 000000000..0278b46ee --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/init.cpp.dot @@ -0,0 +1,59 @@ +digraph iCFG { +15 [label="15: DeclStmt \n n$2=*&par:int * [line 23]\n n$3=*n$2:int [line 23]\n *&v:int =n$3 [line 23]\n REMOVE_TEMPS(n$2,n$3); [line 23]\n NULLIFY(&v,false); [line 23]\n " shape="box"] + + + 15 -> 14 ; +14 [label="14: DeclStmt \n n$1=*&par:int * [line 24]\n *&d:int =n$1 [line 24]\n REMOVE_TEMPS(n$1); [line 24]\n NULLIFY(&d,false); [line 24]\n " shape="box"] + + + 14 -> 13 ; +13 [label="13: DeclStmt \n n$0=*&par:int * [line 25]\n *&p:int *=n$0 [line 25]\n REMOVE_TEMPS(n$0); [line 25]\n NULLIFY(&p,false); [line 25]\n NULLIFY(&par,false); [line 25]\n APPLY_ABSTRACTION; [line 25]\n " shape="box"] + + + 13 -> 12 ; +12 [label="12: Exit init_from_ptr \n " color=yellow style=filled] + + +11 [label="11: Start init_from_ptr\nFormals: par:int *\nLocals: p:int * d:int & v:int \n DECLARE_LOCALS(&return,&p,&d,&v); [line 22]\n NULLIFY(&d,false); [line 22]\n NULLIFY(&p,false); [line 22]\n NULLIFY(&v,false); [line 22]\n " color=yellow style=filled] + + + 11 -> 15 ; +10 [label="10: DeclStmt \n n$0=*&par:int [line 17]\n *&v:int =n$0 [line 17]\n REMOVE_TEMPS(n$0); [line 17]\n NULLIFY(&v,false); [line 17]\n " shape="box"] + + + 10 -> 9 ; +9 [label="9: DeclStmt \n *&d:int =&par [line 18]\n NULLIFY(&d,false); [line 18]\n " shape="box"] + + + 9 -> 8 ; +8 [label="8: DeclStmt \n *&p:int *=&par [line 19]\n NULLIFY(&p,false); [line 19]\n NULLIFY(&par,false); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"] + + + 8 -> 7 ; +7 [label="7: Exit init_from_val \n " color=yellow style=filled] + + +6 [label="6: Start init_from_val\nFormals: par:int \nLocals: p:int * d:int & v:int \n DECLARE_LOCALS(&return,&p,&d,&v); [line 16]\n NULLIFY(&d,false); [line 16]\n NULLIFY(&p,false); [line 16]\n NULLIFY(&v,false); [line 16]\n " color=yellow style=filled] + + + 6 -> 10 ; +5 [label="5: DeclStmt \n n$2=*&par:int & [line 11]\n n$3=*n$2:int [line 11]\n *&v:int =n$3 [line 11]\n REMOVE_TEMPS(n$2,n$3); [line 11]\n NULLIFY(&v,false); [line 11]\n " shape="box"] + + + 5 -> 4 ; +4 [label="4: DeclStmt \n n$1=*&par:int & [line 12]\n *&d:int =n$1 [line 12]\n REMOVE_TEMPS(n$1); [line 12]\n NULLIFY(&d,false); [line 12]\n " shape="box"] + + + 4 -> 3 ; +3 [label="3: DeclStmt \n n$0=*&par:int & [line 13]\n *&p:int *=n$0 [line 13]\n REMOVE_TEMPS(n$0); [line 13]\n NULLIFY(&p,false); [line 13]\n NULLIFY(&par,false); [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit init_from_ref \n " color=yellow style=filled] + + +1 [label="1: Start init_from_ref\nFormals: par:int &\nLocals: p:int * d:int & v:int \n DECLARE_LOCALS(&return,&p,&d,&v); [line 10]\n NULLIFY(&d,false); [line 10]\n NULLIFY(&p,false); [line 10]\n NULLIFY(&v,false); [line 10]\n " color=yellow style=filled] + + + 1 -> 5 ; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/member_access.cpp b/infer/tests/codetoanalyze/cpp/frontend/reference/member_access.cpp new file mode 100644 index 000000000..907663962 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/member_access.cpp @@ -0,0 +1,23 @@ +/* +* 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. +*/ + +struct X { + int f; + int call() {return f;} +}; + +void access_ref(X& x) { + int f = x.f; + int c = x.call(); +} + +void access_ptr(X* x) { + int f = x->f; + int c = x->call(); +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/member_access.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/reference/member_access.cpp.dot new file mode 100644 index 000000000..f1a2f797e --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/member_access.cpp.dot @@ -0,0 +1,43 @@ +digraph iCFG { +11 [label="11: DeclStmt \n n$2=*&x:class X * [line 21]\n n$3=*n$2.f:int [line 21]\n *&f:int =n$3 [line 21]\n REMOVE_TEMPS(n$2,n$3); [line 21]\n NULLIFY(&f,false); [line 21]\n " shape="box"] + + + 11 -> 10 ; +10 [label="10: DeclStmt \n n$0=*&x:class X * [line 22]\n n$1=_fun_X_call(n$0:class X ) [line 22]\n *&c:int =n$1 [line 22]\n REMOVE_TEMPS(n$0,n$1); [line 22]\n NULLIFY(&c,false); [line 22]\n NULLIFY(&x,false); [line 22]\n APPLY_ABSTRACTION; [line 22]\n " shape="box"] + + + 10 -> 9 ; +9 [label="9: Exit access_ptr \n " color=yellow style=filled] + + +8 [label="8: Start access_ptr\nFormals: x:class X *\nLocals: c:int f:int \n DECLARE_LOCALS(&return,&c,&f); [line 20]\n NULLIFY(&c,false); [line 20]\n NULLIFY(&f,false); [line 20]\n " color=yellow style=filled] + + + 8 -> 11 ; +7 [label="7: DeclStmt \n n$2=*&x:class X & [line 16]\n n$3=*n$2.f:int [line 16]\n *&f:int =n$3 [line 16]\n REMOVE_TEMPS(n$2,n$3); [line 16]\n NULLIFY(&f,false); [line 16]\n " shape="box"] + + + 7 -> 6 ; +6 [label="6: DeclStmt \n n$0=*&x:class X & [line 17]\n n$1=_fun_X_call(n$0:class X ) [line 17]\n *&c:int =n$1 [line 17]\n REMOVE_TEMPS(n$0,n$1); [line 17]\n NULLIFY(&c,false); [line 17]\n NULLIFY(&x,false); [line 17]\n APPLY_ABSTRACTION; [line 17]\n " shape="box"] + + + 6 -> 5 ; +5 [label="5: Exit access_ref \n " color=yellow style=filled] + + +4 [label="4: Start access_ref\nFormals: x:class X &\nLocals: c:int f:int \n DECLARE_LOCALS(&return,&c,&f); [line 15]\n NULLIFY(&c,false); [line 15]\n NULLIFY(&f,false); [line 15]\n " color=yellow style=filled] + + + 4 -> 7 ; +3 [label="3: Return Stmt \n n$0=*&this:class X * [line 12]\n n$1=*n$0.f:int [line 12]\n *&return:int =n$1 [line 12]\n REMOVE_TEMPS(n$0,n$1); [line 12]\n NULLIFY(&this,false); [line 12]\n APPLY_ABSTRACTION; [line 12]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit X_call \n " color=yellow style=filled] + + +1 [label="1: Start X_call\nFormals: this:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 12]\n " color=yellow style=filled] + + + 1 -> 3 ; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/member_access_from_return.cpp b/infer/tests/codetoanalyze/cpp/frontend/reference/member_access_from_return.cpp new file mode 100644 index 000000000..4f1e61521 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/member_access_from_return.cpp @@ -0,0 +1,27 @@ +/* +* 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. +*/ + +struct X { + int f; + int call() {return f;} +}; + +X global; +X * get_ptr() {return &global;} +X& get_ref() {return global;} + +void test_ref() { + int f = get_ref().f; + int c = get_ref().call(); +} + +void test_ptr() { + int f = get_ptr()->f; + int c = get_ptr()->call(); +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/member_access_from_return.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/reference/member_access_from_return.cpp.dot new file mode 100644 index 000000000..a13ebee02 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/member_access_from_return.cpp.dot @@ -0,0 +1,65 @@ +digraph iCFG { +17 [label="17: DeclStmt \n n$2=_fun_get_ptr() [line 25]\n n$3=*n$2.f:int [line 25]\n *&f:int =n$3 [line 25]\n REMOVE_TEMPS(n$2,n$3); [line 25]\n NULLIFY(&f,false); [line 25]\n " shape="box"] + + + 17 -> 16 ; +16 [label="16: DeclStmt \n n$0=_fun_get_ptr() [line 26]\n n$1=_fun_X_call(n$0:class X ) [line 26]\n *&c:int =n$1 [line 26]\n REMOVE_TEMPS(n$0,n$1); [line 26]\n NULLIFY(&c,false); [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"] + + + 16 -> 15 ; +15 [label="15: Exit test_ptr \n " color=yellow style=filled] + + +14 [label="14: Start test_ptr\nFormals: \nLocals: c:int f:int \n DECLARE_LOCALS(&return,&c,&f); [line 24]\n NULLIFY(&c,false); [line 24]\n NULLIFY(&f,false); [line 24]\n " color=yellow style=filled] + + + 14 -> 17 ; +13 [label="13: DeclStmt \n n$2=_fun_get_ref() [line 20]\n n$3=*n$2.f:int [line 20]\n *&f:int =n$3 [line 20]\n REMOVE_TEMPS(n$2,n$3); [line 20]\n NULLIFY(&f,false); [line 20]\n " shape="box"] + + + 13 -> 12 ; +12 [label="12: DeclStmt \n n$0=_fun_get_ref() [line 21]\n n$1=_fun_X_call(n$0:class X ) [line 21]\n *&c:int =n$1 [line 21]\n REMOVE_TEMPS(n$0,n$1); [line 21]\n NULLIFY(&c,false); [line 21]\n APPLY_ABSTRACTION; [line 21]\n " shape="box"] + + + 12 -> 11 ; +11 [label="11: Exit test_ref \n " color=yellow style=filled] + + +10 [label="10: Start test_ref\nFormals: \nLocals: c:int f:int \n DECLARE_LOCALS(&return,&c,&f); [line 19]\n NULLIFY(&c,false); [line 19]\n NULLIFY(&f,false); [line 19]\n " color=yellow style=filled] + + + 10 -> 13 ; +9 [label="9: Return Stmt \n *&return:class X &=&#GB$global [line 17]\n APPLY_ABSTRACTION; [line 17]\n " shape="box"] + + + 9 -> 8 ; +8 [label="8: Exit get_ref \n " color=yellow style=filled] + + +7 [label="7: Start get_ref\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 17]\n " color=yellow style=filled] + + + 7 -> 9 ; +6 [label="6: Return Stmt \n *&return:class X *=&#GB$global [line 16]\n APPLY_ABSTRACTION; [line 16]\n " shape="box"] + + + 6 -> 5 ; +5 [label="5: Exit get_ptr \n " color=yellow style=filled] + + +4 [label="4: Start get_ptr\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 16]\n " color=yellow style=filled] + + + 4 -> 6 ; +3 [label="3: Return Stmt \n n$0=*&this:class X * [line 12]\n n$1=*n$0.f:int [line 12]\n *&return:int =n$1 [line 12]\n REMOVE_TEMPS(n$0,n$1); [line 12]\n NULLIFY(&this,false); [line 12]\n APPLY_ABSTRACTION; [line 12]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit X_call \n " color=yellow style=filled] + + +1 [label="1: Start X_call\nFormals: this:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 12]\n " color=yellow style=filled] + + + 1 -> 3 ; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/reference_struct_e2e.cpp b/infer/tests/codetoanalyze/cpp/frontend/reference/reference_struct_e2e.cpp new file mode 100644 index 000000000..29f7035ef --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/reference_struct_e2e.cpp @@ -0,0 +1,139 @@ +/* +* 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. +*/ + +struct X { + int f; + void nonzero() { f = 1; } + void zero() { f = 0; } + int div() { return 1/f; } +}; + +void zero_ptr(X *x) { + x->zero(); +} + +void nonzero_ptr(X *x) { + x->nonzero(); +} + +void set_field_ptr(X *x, int val) { + x->f = val; +} + +void zero_ref(X &x) { + x.zero(); +} + +void nonzero_ref(X &x) { + x.nonzero(); +} + +void set_field_ref(X &x, int val) { + x.f = val; +} + +X global; +X* get_global_ptr() { return &global;} +X& get_global_ref() { return global;} + +int method_div0_ptr(X *x) { + if (x) { + zero_ptr(x); + return x->div(); + } +} + +int method_div1_ptr(X *x) { + if (x) { + nonzero_ptr(x); + return x->div(); + } +} + +int field_div0_ptr(X *x) { + if(x) { + set_field_ptr(x, 0); + return x->div(); + } +} + +int field_div1_ptr(X *x) { + if(x) { + set_field_ptr(x, 1); + return x->div(); + } +} + +int get_global_ptr_div0_method() { + get_global_ptr()->f = 1; + get_global_ptr()->zero(); + get_global_ptr()->div(); +} + +int get_global_ptr_div1_method() { + get_global_ptr()->f = 0; + get_global_ptr()->nonzero(); + get_global_ptr()->div(); +} + +int get_global_ptr_div0_field() { + get_global_ptr()->nonzero(); + get_global_ptr()->f = 0; + get_global_ptr()->div(); +} + +int get_global_ptr_div1_field() { + get_global_ptr()->zero(); + get_global_ptr()->f = 1; + get_global_ptr()->div(); +} + +int method_div0_ref(X &x) { + zero_ref(x); + return x.div(); +} + +int method_div1_ref(X &x) { + nonzero_ref(x); + return x.div(); +} + +int field_div0_ref(X &x) { + set_field_ref(x, 0); + return x.div(); +} + +int field_div1_ref(X &x) { + set_field_ref(x, 1); + return x.div(); +} + +int get_global_ref_div0_method() { + get_global_ref().f = 1; + get_global_ref().zero(); + get_global_ref().div(); +} + +int get_global_ref_div1_method() { + get_global_ref().f = 0; + get_global_ref().nonzero(); + get_global_ref().div(); +} + +int get_global_ref_div0_field() { + get_global_ref().nonzero(); + get_global_ref().f = 0; + get_global_ref().div(); +} + +int get_global_ref_div1_field() { + get_global_ref().zero(); + get_global_ref().f = 1; + get_global_ref().div(); +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/reference_struct_e2e.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/reference/reference_struct_e2e.cpp.dot new file mode 100644 index 000000000..cf1e78788 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/reference_struct_e2e.cpp.dot @@ -0,0 +1,447 @@ +digraph iCFG { +117 [label="117: Call _fun_X_zero \n n$3=_fun_get_global_ref() [line 136]\n _fun_X_zero(n$3:class X ) [line 136]\n REMOVE_TEMPS(n$3); [line 136]\n " shape="box"] + + + 117 -> 116 ; +116 [label="116: BinaryOperatorStmt: Assign \n n$2=_fun_get_global_ref() [line 137]\n *n$2.f:int =1 [line 137]\n REMOVE_TEMPS(n$2); [line 137]\n " shape="box"] + + + 116 -> 115 ; +115 [label="115: Call _fun_X_div \n n$0=_fun_get_global_ref() [line 138]\n n$1=_fun_X_div(n$0:class X ) [line 138]\n REMOVE_TEMPS(n$0,n$1); [line 138]\n APPLY_ABSTRACTION; [line 138]\n " shape="box"] + + + 115 -> 114 ; +114 [label="114: Exit get_global_ref_div1_field \n " color=yellow style=filled] + + +113 [label="113: Start get_global_ref_div1_field\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 135]\n " color=yellow style=filled] + + + 113 -> 117 ; +112 [label="112: Call _fun_X_nonzero \n n$3=_fun_get_global_ref() [line 130]\n _fun_X_nonzero(n$3:class X ) [line 130]\n REMOVE_TEMPS(n$3); [line 130]\n " shape="box"] + + + 112 -> 111 ; +111 [label="111: BinaryOperatorStmt: Assign \n n$2=_fun_get_global_ref() [line 131]\n *n$2.f:int =0 [line 131]\n REMOVE_TEMPS(n$2); [line 131]\n " shape="box"] + + + 111 -> 110 ; +110 [label="110: Call _fun_X_div \n n$0=_fun_get_global_ref() [line 132]\n n$1=_fun_X_div(n$0:class X ) [line 132]\n REMOVE_TEMPS(n$0,n$1); [line 132]\n APPLY_ABSTRACTION; [line 132]\n " shape="box"] + + + 110 -> 109 ; +109 [label="109: Exit get_global_ref_div0_field \n " color=yellow style=filled] + + +108 [label="108: Start get_global_ref_div0_field\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 129]\n " color=yellow style=filled] + + + 108 -> 112 ; +107 [label="107: BinaryOperatorStmt: Assign \n n$3=_fun_get_global_ref() [line 124]\n *n$3.f:int =0 [line 124]\n REMOVE_TEMPS(n$3); [line 124]\n " shape="box"] + + + 107 -> 106 ; +106 [label="106: Call _fun_X_nonzero \n n$2=_fun_get_global_ref() [line 125]\n _fun_X_nonzero(n$2:class X ) [line 125]\n REMOVE_TEMPS(n$2); [line 125]\n " shape="box"] + + + 106 -> 105 ; +105 [label="105: Call _fun_X_div \n n$0=_fun_get_global_ref() [line 126]\n n$1=_fun_X_div(n$0:class X ) [line 126]\n REMOVE_TEMPS(n$0,n$1); [line 126]\n APPLY_ABSTRACTION; [line 126]\n " shape="box"] + + + 105 -> 104 ; +104 [label="104: Exit get_global_ref_div1_method \n " color=yellow style=filled] + + +103 [label="103: Start get_global_ref_div1_method\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 123]\n " color=yellow style=filled] + + + 103 -> 107 ; +102 [label="102: BinaryOperatorStmt: Assign \n n$3=_fun_get_global_ref() [line 118]\n *n$3.f:int =1 [line 118]\n REMOVE_TEMPS(n$3); [line 118]\n " shape="box"] + + + 102 -> 101 ; +101 [label="101: Call _fun_X_zero \n n$2=_fun_get_global_ref() [line 119]\n _fun_X_zero(n$2:class X ) [line 119]\n REMOVE_TEMPS(n$2); [line 119]\n " shape="box"] + + + 101 -> 100 ; +100 [label="100: Call _fun_X_div \n n$0=_fun_get_global_ref() [line 120]\n n$1=_fun_X_div(n$0:class X ) [line 120]\n REMOVE_TEMPS(n$0,n$1); [line 120]\n APPLY_ABSTRACTION; [line 120]\n " shape="box"] + + + 100 -> 99 ; +99 [label="99: Exit get_global_ref_div0_method \n " color=yellow style=filled] + + +98 [label="98: Start get_global_ref_div0_method\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 117]\n " color=yellow style=filled] + + + 98 -> 102 ; +97 [label="97: Call _fun_set_field_ref \n n$2=*&x:class X & [line 113]\n _fun_set_field_ref(n$2:class X ,1:int ) [line 113]\n REMOVE_TEMPS(n$2); [line 113]\n " shape="box"] + + + 97 -> 96 ; +96 [label="96: Return Stmt \n n$0=*&x:class X & [line 114]\n n$1=_fun_X_div(n$0:class X ) [line 114]\n *&return:int =n$1 [line 114]\n REMOVE_TEMPS(n$0,n$1); [line 114]\n NULLIFY(&x,false); [line 114]\n APPLY_ABSTRACTION; [line 114]\n " shape="box"] + + + 96 -> 95 ; +95 [label="95: Exit field_div1_ref \n " color=yellow style=filled] + + +94 [label="94: Start field_div1_ref\nFormals: x:class X &\nLocals: \n DECLARE_LOCALS(&return); [line 112]\n " color=yellow style=filled] + + + 94 -> 97 ; +93 [label="93: Call _fun_set_field_ref \n n$2=*&x:class X & [line 108]\n _fun_set_field_ref(n$2:class X ,0:int ) [line 108]\n REMOVE_TEMPS(n$2); [line 108]\n " shape="box"] + + + 93 -> 92 ; +92 [label="92: Return Stmt \n n$0=*&x:class X & [line 109]\n n$1=_fun_X_div(n$0:class X ) [line 109]\n *&return:int =n$1 [line 109]\n REMOVE_TEMPS(n$0,n$1); [line 109]\n NULLIFY(&x,false); [line 109]\n APPLY_ABSTRACTION; [line 109]\n " shape="box"] + + + 92 -> 91 ; +91 [label="91: Exit field_div0_ref \n " color=yellow style=filled] + + +90 [label="90: Start field_div0_ref\nFormals: x:class X &\nLocals: \n DECLARE_LOCALS(&return); [line 107]\n " color=yellow style=filled] + + + 90 -> 93 ; +89 [label="89: Call _fun_nonzero_ref \n n$2=*&x:class X & [line 103]\n _fun_nonzero_ref(n$2:class X ) [line 103]\n REMOVE_TEMPS(n$2); [line 103]\n " shape="box"] + + + 89 -> 88 ; +88 [label="88: Return Stmt \n n$0=*&x:class X & [line 104]\n n$1=_fun_X_div(n$0:class X ) [line 104]\n *&return:int =n$1 [line 104]\n REMOVE_TEMPS(n$0,n$1); [line 104]\n NULLIFY(&x,false); [line 104]\n APPLY_ABSTRACTION; [line 104]\n " shape="box"] + + + 88 -> 87 ; +87 [label="87: Exit method_div1_ref \n " color=yellow style=filled] + + +86 [label="86: Start method_div1_ref\nFormals: x:class X &\nLocals: \n DECLARE_LOCALS(&return); [line 102]\n " color=yellow style=filled] + + + 86 -> 89 ; +85 [label="85: Call _fun_zero_ref \n n$2=*&x:class X & [line 98]\n _fun_zero_ref(n$2:class X ) [line 98]\n REMOVE_TEMPS(n$2); [line 98]\n " shape="box"] + + + 85 -> 84 ; +84 [label="84: Return Stmt \n n$0=*&x:class X & [line 99]\n n$1=_fun_X_div(n$0:class X ) [line 99]\n *&return:int =n$1 [line 99]\n REMOVE_TEMPS(n$0,n$1); [line 99]\n NULLIFY(&x,false); [line 99]\n APPLY_ABSTRACTION; [line 99]\n " shape="box"] + + + 84 -> 83 ; +83 [label="83: Exit method_div0_ref \n " color=yellow style=filled] + + +82 [label="82: Start method_div0_ref\nFormals: x:class X &\nLocals: \n DECLARE_LOCALS(&return); [line 97]\n " color=yellow style=filled] + + + 82 -> 85 ; +81 [label="81: Call _fun_X_zero \n n$3=_fun_get_global_ptr() [line 92]\n _fun_X_zero(n$3:class X ) [line 92]\n REMOVE_TEMPS(n$3); [line 92]\n " shape="box"] + + + 81 -> 80 ; +80 [label="80: BinaryOperatorStmt: Assign \n n$2=_fun_get_global_ptr() [line 93]\n *n$2.f:int =1 [line 93]\n REMOVE_TEMPS(n$2); [line 93]\n " shape="box"] + + + 80 -> 79 ; +79 [label="79: Call _fun_X_div \n n$0=_fun_get_global_ptr() [line 94]\n n$1=_fun_X_div(n$0:class X ) [line 94]\n REMOVE_TEMPS(n$0,n$1); [line 94]\n APPLY_ABSTRACTION; [line 94]\n " shape="box"] + + + 79 -> 78 ; +78 [label="78: Exit get_global_ptr_div1_field \n " color=yellow style=filled] + + +77 [label="77: Start get_global_ptr_div1_field\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 91]\n " color=yellow style=filled] + + + 77 -> 81 ; +76 [label="76: Call _fun_X_nonzero \n n$3=_fun_get_global_ptr() [line 86]\n _fun_X_nonzero(n$3:class X ) [line 86]\n REMOVE_TEMPS(n$3); [line 86]\n " shape="box"] + + + 76 -> 75 ; +75 [label="75: BinaryOperatorStmt: Assign \n n$2=_fun_get_global_ptr() [line 87]\n *n$2.f:int =0 [line 87]\n REMOVE_TEMPS(n$2); [line 87]\n " shape="box"] + + + 75 -> 74 ; +74 [label="74: Call _fun_X_div \n n$0=_fun_get_global_ptr() [line 88]\n n$1=_fun_X_div(n$0:class X ) [line 88]\n REMOVE_TEMPS(n$0,n$1); [line 88]\n APPLY_ABSTRACTION; [line 88]\n " shape="box"] + + + 74 -> 73 ; +73 [label="73: Exit get_global_ptr_div0_field \n " color=yellow style=filled] + + +72 [label="72: Start get_global_ptr_div0_field\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 85]\n " color=yellow style=filled] + + + 72 -> 76 ; +71 [label="71: BinaryOperatorStmt: Assign \n n$3=_fun_get_global_ptr() [line 80]\n *n$3.f:int =0 [line 80]\n REMOVE_TEMPS(n$3); [line 80]\n " shape="box"] + + + 71 -> 70 ; +70 [label="70: Call _fun_X_nonzero \n n$2=_fun_get_global_ptr() [line 81]\n _fun_X_nonzero(n$2:class X ) [line 81]\n REMOVE_TEMPS(n$2); [line 81]\n " shape="box"] + + + 70 -> 69 ; +69 [label="69: Call _fun_X_div \n n$0=_fun_get_global_ptr() [line 82]\n n$1=_fun_X_div(n$0:class X ) [line 82]\n REMOVE_TEMPS(n$0,n$1); [line 82]\n APPLY_ABSTRACTION; [line 82]\n " shape="box"] + + + 69 -> 68 ; +68 [label="68: Exit get_global_ptr_div1_method \n " color=yellow style=filled] + + +67 [label="67: Start get_global_ptr_div1_method\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 79]\n " color=yellow style=filled] + + + 67 -> 71 ; +66 [label="66: BinaryOperatorStmt: Assign \n n$3=_fun_get_global_ptr() [line 74]\n *n$3.f:int =1 [line 74]\n REMOVE_TEMPS(n$3); [line 74]\n " shape="box"] + + + 66 -> 65 ; +65 [label="65: Call _fun_X_zero \n n$2=_fun_get_global_ptr() [line 75]\n _fun_X_zero(n$2:class X ) [line 75]\n REMOVE_TEMPS(n$2); [line 75]\n " shape="box"] + + + 65 -> 64 ; +64 [label="64: Call _fun_X_div \n n$0=_fun_get_global_ptr() [line 76]\n n$1=_fun_X_div(n$0:class X ) [line 76]\n REMOVE_TEMPS(n$0,n$1); [line 76]\n APPLY_ABSTRACTION; [line 76]\n " shape="box"] + + + 64 -> 63 ; +63 [label="63: Exit get_global_ptr_div0_method \n " color=yellow style=filled] + + +62 [label="62: Start get_global_ptr_div0_method\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 73]\n " color=yellow style=filled] + + + 62 -> 66 ; +61 [label="61: Call _fun_set_field_ptr \n n$3=*&x:class X * [line 68]\n _fun_set_field_ptr(n$3:class X *,1:int ) [line 68]\n REMOVE_TEMPS(n$3); [line 68]\n " shape="box"] + + + 61 -> 60 ; +60 [label="60: Return Stmt \n n$1=*&x:class X * [line 69]\n n$2=_fun_X_div(n$1:class X ) [line 69]\n *&return:int =n$2 [line 69]\n REMOVE_TEMPS(n$1,n$2); [line 69]\n NULLIFY(&x,false); [line 69]\n APPLY_ABSTRACTION; [line 69]\n " shape="box"] + + + 60 -> 56 ; +59 [label="59: Prune (false branch) \n n$0=*&x:class X * [line 67]\n PRUNE((n$0 == 0), false); [line 67]\n REMOVE_TEMPS(n$0); [line 67]\n " shape="invhouse"] + + + 59 -> 57 ; +58 [label="58: Prune (true branch) \n n$0=*&x:class X * [line 67]\n PRUNE((n$0 != 0), true); [line 67]\n REMOVE_TEMPS(n$0); [line 67]\n " shape="invhouse"] + + + 58 -> 61 ; +57 [label="57: + \n NULLIFY(&x,false); [line 67]\n " ] + + + 57 -> 56 ; +56 [label="56: Exit field_div1_ptr \n " color=yellow style=filled] + + +55 [label="55: Start field_div1_ptr\nFormals: x:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 66]\n " color=yellow style=filled] + + + 55 -> 58 ; + 55 -> 59 ; +54 [label="54: Call _fun_set_field_ptr \n n$3=*&x:class X * [line 61]\n _fun_set_field_ptr(n$3:class X *,0:int ) [line 61]\n REMOVE_TEMPS(n$3); [line 61]\n " shape="box"] + + + 54 -> 53 ; +53 [label="53: Return Stmt \n n$1=*&x:class X * [line 62]\n n$2=_fun_X_div(n$1:class X ) [line 62]\n *&return:int =n$2 [line 62]\n REMOVE_TEMPS(n$1,n$2); [line 62]\n NULLIFY(&x,false); [line 62]\n APPLY_ABSTRACTION; [line 62]\n " shape="box"] + + + 53 -> 49 ; +52 [label="52: Prune (false branch) \n n$0=*&x:class X * [line 60]\n PRUNE((n$0 == 0), false); [line 60]\n REMOVE_TEMPS(n$0); [line 60]\n " shape="invhouse"] + + + 52 -> 50 ; +51 [label="51: Prune (true branch) \n n$0=*&x:class X * [line 60]\n PRUNE((n$0 != 0), true); [line 60]\n REMOVE_TEMPS(n$0); [line 60]\n " shape="invhouse"] + + + 51 -> 54 ; +50 [label="50: + \n NULLIFY(&x,false); [line 60]\n " ] + + + 50 -> 49 ; +49 [label="49: Exit field_div0_ptr \n " color=yellow style=filled] + + +48 [label="48: Start field_div0_ptr\nFormals: x:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 59]\n " color=yellow style=filled] + + + 48 -> 51 ; + 48 -> 52 ; +47 [label="47: Call _fun_nonzero_ptr \n n$3=*&x:class X * [line 54]\n _fun_nonzero_ptr(n$3:class X *) [line 54]\n REMOVE_TEMPS(n$3); [line 54]\n " shape="box"] + + + 47 -> 46 ; +46 [label="46: Return Stmt \n n$1=*&x:class X * [line 55]\n n$2=_fun_X_div(n$1:class X ) [line 55]\n *&return:int =n$2 [line 55]\n REMOVE_TEMPS(n$1,n$2); [line 55]\n NULLIFY(&x,false); [line 55]\n APPLY_ABSTRACTION; [line 55]\n " shape="box"] + + + 46 -> 42 ; +45 [label="45: Prune (false branch) \n n$0=*&x:class X * [line 53]\n PRUNE((n$0 == 0), false); [line 53]\n REMOVE_TEMPS(n$0); [line 53]\n " shape="invhouse"] + + + 45 -> 43 ; +44 [label="44: Prune (true branch) \n n$0=*&x:class X * [line 53]\n PRUNE((n$0 != 0), true); [line 53]\n REMOVE_TEMPS(n$0); [line 53]\n " shape="invhouse"] + + + 44 -> 47 ; +43 [label="43: + \n NULLIFY(&x,false); [line 53]\n " ] + + + 43 -> 42 ; +42 [label="42: Exit method_div1_ptr \n " color=yellow style=filled] + + +41 [label="41: Start method_div1_ptr\nFormals: x:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 52]\n " color=yellow style=filled] + + + 41 -> 44 ; + 41 -> 45 ; +40 [label="40: Call _fun_zero_ptr \n n$3=*&x:class X * [line 47]\n _fun_zero_ptr(n$3:class X *) [line 47]\n REMOVE_TEMPS(n$3); [line 47]\n " shape="box"] + + + 40 -> 39 ; +39 [label="39: Return Stmt \n n$1=*&x:class X * [line 48]\n n$2=_fun_X_div(n$1:class X ) [line 48]\n *&return:int =n$2 [line 48]\n REMOVE_TEMPS(n$1,n$2); [line 48]\n NULLIFY(&x,false); [line 48]\n APPLY_ABSTRACTION; [line 48]\n " shape="box"] + + + 39 -> 35 ; +38 [label="38: Prune (false branch) \n n$0=*&x:class X * [line 46]\n PRUNE((n$0 == 0), false); [line 46]\n REMOVE_TEMPS(n$0); [line 46]\n " shape="invhouse"] + + + 38 -> 36 ; +37 [label="37: Prune (true branch) \n n$0=*&x:class X * [line 46]\n PRUNE((n$0 != 0), true); [line 46]\n REMOVE_TEMPS(n$0); [line 46]\n " shape="invhouse"] + + + 37 -> 40 ; +36 [label="36: + \n NULLIFY(&x,false); [line 46]\n " ] + + + 36 -> 35 ; +35 [label="35: Exit method_div0_ptr \n " color=yellow style=filled] + + +34 [label="34: Start method_div0_ptr\nFormals: x:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 45]\n " color=yellow style=filled] + + + 34 -> 37 ; + 34 -> 38 ; +33 [label="33: Return Stmt \n *&return:class X &=&#GB$global [line 43]\n APPLY_ABSTRACTION; [line 43]\n " shape="box"] + + + 33 -> 32 ; +32 [label="32: Exit get_global_ref \n " color=yellow style=filled] + + +31 [label="31: Start get_global_ref\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 43]\n " color=yellow style=filled] + + + 31 -> 33 ; +30 [label="30: Return Stmt \n *&return:class X *=&#GB$global [line 42]\n APPLY_ABSTRACTION; [line 42]\n " shape="box"] + + + 30 -> 29 ; +29 [label="29: Exit get_global_ptr \n " color=yellow style=filled] + + +28 [label="28: Start get_global_ptr\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 42]\n " color=yellow style=filled] + + + 28 -> 30 ; +27 [label="27: BinaryOperatorStmt: Assign \n n$0=*&x:class X & [line 38]\n n$1=*&val:int [line 38]\n *n$0.f:int =n$1 [line 38]\n REMOVE_TEMPS(n$0,n$1); [line 38]\n NULLIFY(&val,false); [line 38]\n NULLIFY(&x,false); [line 38]\n APPLY_ABSTRACTION; [line 38]\n " shape="box"] + + + 27 -> 26 ; +26 [label="26: Exit set_field_ref \n " color=yellow style=filled] + + +25 [label="25: Start set_field_ref\nFormals: x:class X & val:int \nLocals: \n DECLARE_LOCALS(&return); [line 37]\n " color=yellow style=filled] + + + 25 -> 27 ; +24 [label="24: Call _fun_X_nonzero \n n$0=*&x:class X & [line 34]\n _fun_X_nonzero(n$0:class X ) [line 34]\n REMOVE_TEMPS(n$0); [line 34]\n NULLIFY(&x,false); [line 34]\n APPLY_ABSTRACTION; [line 34]\n " shape="box"] + + + 24 -> 23 ; +23 [label="23: Exit nonzero_ref \n " color=yellow style=filled] + + +22 [label="22: Start nonzero_ref\nFormals: x:class X &\nLocals: \n DECLARE_LOCALS(&return); [line 33]\n " color=yellow style=filled] + + + 22 -> 24 ; +21 [label="21: Call _fun_X_zero \n n$0=*&x:class X & [line 30]\n _fun_X_zero(n$0:class X ) [line 30]\n REMOVE_TEMPS(n$0); [line 30]\n NULLIFY(&x,false); [line 30]\n APPLY_ABSTRACTION; [line 30]\n " shape="box"] + + + 21 -> 20 ; +20 [label="20: Exit zero_ref \n " color=yellow style=filled] + + +19 [label="19: Start zero_ref\nFormals: x:class X &\nLocals: \n DECLARE_LOCALS(&return); [line 29]\n " color=yellow style=filled] + + + 19 -> 21 ; +18 [label="18: BinaryOperatorStmt: Assign \n n$0=*&x:class X * [line 26]\n n$1=*&val:int [line 26]\n *n$0.f:int =n$1 [line 26]\n REMOVE_TEMPS(n$0,n$1); [line 26]\n NULLIFY(&val,false); [line 26]\n NULLIFY(&x,false); [line 26]\n APPLY_ABSTRACTION; [line 26]\n " shape="box"] + + + 18 -> 17 ; +17 [label="17: Exit set_field_ptr \n " color=yellow style=filled] + + +16 [label="16: Start set_field_ptr\nFormals: x:class X * val:int \nLocals: \n DECLARE_LOCALS(&return); [line 25]\n " color=yellow style=filled] + + + 16 -> 18 ; +15 [label="15: Call _fun_X_nonzero \n n$0=*&x:class X * [line 22]\n _fun_X_nonzero(n$0:class X ) [line 22]\n REMOVE_TEMPS(n$0); [line 22]\n NULLIFY(&x,false); [line 22]\n APPLY_ABSTRACTION; [line 22]\n " shape="box"] + + + 15 -> 14 ; +14 [label="14: Exit nonzero_ptr \n " color=yellow style=filled] + + +13 [label="13: Start nonzero_ptr\nFormals: x:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 21]\n " color=yellow style=filled] + + + 13 -> 15 ; +12 [label="12: Call _fun_X_zero \n n$0=*&x:class X * [line 18]\n _fun_X_zero(n$0:class X ) [line 18]\n REMOVE_TEMPS(n$0); [line 18]\n NULLIFY(&x,false); [line 18]\n APPLY_ABSTRACTION; [line 18]\n " shape="box"] + + + 12 -> 11 ; +11 [label="11: Exit zero_ptr \n " color=yellow style=filled] + + +10 [label="10: Start zero_ptr\nFormals: x:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 17]\n " color=yellow style=filled] + + + 10 -> 12 ; +9 [label="9: Return Stmt \n n$0=*&this:class X * [line 14]\n n$1=*n$0.f:int [line 14]\n *&return:int =(1 / n$1) [line 14]\n REMOVE_TEMPS(n$0,n$1); [line 14]\n NULLIFY(&this,false); [line 14]\n APPLY_ABSTRACTION; [line 14]\n " shape="box"] + + + 9 -> 8 ; +8 [label="8: Exit X_div \n " color=yellow style=filled] + + +7 [label="7: Start X_div\nFormals: this:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 14]\n " color=yellow style=filled] + + + 7 -> 9 ; +6 [label="6: BinaryOperatorStmt: Assign \n n$0=*&this:class X * [line 13]\n *n$0.f:int =0 [line 13]\n REMOVE_TEMPS(n$0); [line 13]\n NULLIFY(&this,false); [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"] + + + 6 -> 5 ; +5 [label="5: Exit X_zero \n " color=yellow style=filled] + + +4 [label="4: Start X_zero\nFormals: this:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 13]\n " color=yellow style=filled] + + + 4 -> 6 ; +3 [label="3: BinaryOperatorStmt: Assign \n n$0=*&this:class X * [line 12]\n *n$0.f:int =1 [line 12]\n REMOVE_TEMPS(n$0); [line 12]\n NULLIFY(&this,false); [line 12]\n APPLY_ABSTRACTION; [line 12]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit X_nonzero \n " color=yellow style=filled] + + +1 [label="1: Start X_nonzero\nFormals: this:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 12]\n " color=yellow style=filled] + + + 1 -> 3 ; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/reference_type_e2e.cpp b/infer/tests/codetoanalyze/cpp/frontend/reference/reference_type_e2e.cpp new file mode 100644 index 000000000..746b280f1 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/reference_type_e2e.cpp @@ -0,0 +1,51 @@ +/* +* 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. +*/ + +void zero_ptr(int* p) { *p = 0; } +void zero_ref(int& p) { p = 0; } + +int ptr_div0() { + int a = 2; + int* p = &a; + *p = 0; + return 1/a; +} + +int ptr_div0_function() { + int a = 2; + zero_ptr(&a); + return 1/a; +} + +int ptr_div0_function_temp_var() { + int a = 2; + int *r = &a; + zero_ptr(r); + return 1/a; +} + +int ref_div0() { + int a = 2; + int& r = a; + r = 0; + return 1/a; +} + +int ref_div0_function() { + int a = 2; + zero_ref(a); + return 1/a; +} + +int ref_div0_function_temp_var() { + int a = 2; + int &r = a; + zero_ref(r); + return 1/a; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/reference_type_e2e.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/reference/reference_type_e2e.cpp.dot new file mode 100644 index 000000000..9cb8c64f6 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/reference_type_e2e.cpp.dot @@ -0,0 +1,154 @@ +digraph iCFG { +40 [label="40: DeclStmt \n *&a:int =2 [line 47]\n " shape="box"] + + + 40 -> 39 ; +39 [label="39: DeclStmt \n *&r:int =&a [line 48]\n " shape="box"] + + + 39 -> 38 ; +38 [label="38: Call _fun_zero_ref \n n$1=*&r:int & [line 49]\n _fun_zero_ref(n$1:int ) [line 49]\n REMOVE_TEMPS(n$1); [line 49]\n NULLIFY(&r,false); [line 49]\n " shape="box"] + + + 38 -> 37 ; +37 [label="37: Return Stmt \n n$0=*&a:int [line 50]\n *&return:int =(1 / n$0) [line 50]\n REMOVE_TEMPS(n$0); [line 50]\n NULLIFY(&a,false); [line 50]\n APPLY_ABSTRACTION; [line 50]\n " shape="box"] + + + 37 -> 36 ; +36 [label="36: Exit ref_div0_function_temp_var \n " color=yellow style=filled] + + +35 [label="35: Start ref_div0_function_temp_var\nFormals: \nLocals: r:int & a:int \n DECLARE_LOCALS(&return,&r,&a); [line 46]\n NULLIFY(&r,false); [line 46]\n " color=yellow style=filled] + + + 35 -> 40 ; +34 [label="34: DeclStmt \n *&a:int =2 [line 41]\n " shape="box"] + + + 34 -> 33 ; +33 [label="33: Call _fun_zero_ref \n _fun_zero_ref(&a:int ) [line 42]\n " shape="box"] + + + 33 -> 32 ; +32 [label="32: Return Stmt \n n$0=*&a:int [line 43]\n *&return:int =(1 / n$0) [line 43]\n REMOVE_TEMPS(n$0); [line 43]\n NULLIFY(&a,false); [line 43]\n APPLY_ABSTRACTION; [line 43]\n " shape="box"] + + + 32 -> 31 ; +31 [label="31: Exit ref_div0_function \n " color=yellow style=filled] + + +30 [label="30: Start ref_div0_function\nFormals: \nLocals: a:int \n DECLARE_LOCALS(&return,&a); [line 40]\n " color=yellow style=filled] + + + 30 -> 34 ; +29 [label="29: DeclStmt \n *&a:int =2 [line 34]\n " shape="box"] + + + 29 -> 28 ; +28 [label="28: DeclStmt \n *&r:int =&a [line 35]\n " shape="box"] + + + 28 -> 27 ; +27 [label="27: BinaryOperatorStmt: Assign \n n$1=*&r:int & [line 36]\n *n$1:int =0 [line 36]\n REMOVE_TEMPS(n$1); [line 36]\n NULLIFY(&r,false); [line 36]\n " shape="box"] + + + 27 -> 26 ; +26 [label="26: Return Stmt \n n$0=*&a:int [line 37]\n *&return:int =(1 / n$0) [line 37]\n REMOVE_TEMPS(n$0); [line 37]\n NULLIFY(&a,false); [line 37]\n APPLY_ABSTRACTION; [line 37]\n " shape="box"] + + + 26 -> 25 ; +25 [label="25: Exit ref_div0 \n " color=yellow style=filled] + + +24 [label="24: Start ref_div0\nFormals: \nLocals: r:int & a:int \n DECLARE_LOCALS(&return,&r,&a); [line 33]\n NULLIFY(&r,false); [line 33]\n " color=yellow style=filled] + + + 24 -> 29 ; +23 [label="23: DeclStmt \n *&a:int =2 [line 27]\n " shape="box"] + + + 23 -> 22 ; +22 [label="22: DeclStmt \n *&r:int *=&a [line 28]\n " shape="box"] + + + 22 -> 21 ; +21 [label="21: Call _fun_zero_ptr \n n$1=*&r:int * [line 29]\n _fun_zero_ptr(n$1:int *) [line 29]\n REMOVE_TEMPS(n$1); [line 29]\n NULLIFY(&r,false); [line 29]\n " shape="box"] + + + 21 -> 20 ; +20 [label="20: Return Stmt \n n$0=*&a:int [line 30]\n *&return:int =(1 / n$0) [line 30]\n REMOVE_TEMPS(n$0); [line 30]\n NULLIFY(&a,false); [line 30]\n APPLY_ABSTRACTION; [line 30]\n " shape="box"] + + + 20 -> 19 ; +19 [label="19: Exit ptr_div0_function_temp_var \n " color=yellow style=filled] + + +18 [label="18: Start ptr_div0_function_temp_var\nFormals: \nLocals: r:int * a:int \n DECLARE_LOCALS(&return,&r,&a); [line 26]\n NULLIFY(&r,false); [line 26]\n " color=yellow style=filled] + + + 18 -> 23 ; +17 [label="17: DeclStmt \n *&a:int =2 [line 21]\n " shape="box"] + + + 17 -> 16 ; +16 [label="16: Call _fun_zero_ptr \n _fun_zero_ptr(&a:int *) [line 22]\n " shape="box"] + + + 16 -> 15 ; +15 [label="15: Return Stmt \n n$0=*&a:int [line 23]\n *&return:int =(1 / n$0) [line 23]\n REMOVE_TEMPS(n$0); [line 23]\n NULLIFY(&a,false); [line 23]\n APPLY_ABSTRACTION; [line 23]\n " shape="box"] + + + 15 -> 14 ; +14 [label="14: Exit ptr_div0_function \n " color=yellow style=filled] + + +13 [label="13: Start ptr_div0_function\nFormals: \nLocals: a:int \n DECLARE_LOCALS(&return,&a); [line 20]\n " color=yellow style=filled] + + + 13 -> 17 ; +12 [label="12: DeclStmt \n *&a:int =2 [line 14]\n " shape="box"] + + + 12 -> 11 ; +11 [label="11: DeclStmt \n *&p:int *=&a [line 15]\n " shape="box"] + + + 11 -> 10 ; +10 [label="10: BinaryOperatorStmt: Assign \n n$1=*&p:int * [line 16]\n *n$1:int =0 [line 16]\n REMOVE_TEMPS(n$1); [line 16]\n NULLIFY(&p,false); [line 16]\n " shape="box"] + + + 10 -> 9 ; +9 [label="9: Return Stmt \n n$0=*&a:int [line 17]\n *&return:int =(1 / n$0) [line 17]\n REMOVE_TEMPS(n$0); [line 17]\n NULLIFY(&a,false); [line 17]\n APPLY_ABSTRACTION; [line 17]\n " shape="box"] + + + 9 -> 8 ; +8 [label="8: Exit ptr_div0 \n " color=yellow style=filled] + + +7 [label="7: Start ptr_div0\nFormals: \nLocals: p:int * a:int \n DECLARE_LOCALS(&return,&p,&a); [line 13]\n NULLIFY(&p,false); [line 13]\n " color=yellow style=filled] + + + 7 -> 12 ; +6 [label="6: BinaryOperatorStmt: Assign \n n$0=*&p:int & [line 11]\n *n$0:int =0 [line 11]\n REMOVE_TEMPS(n$0); [line 11]\n NULLIFY(&p,false); [line 11]\n APPLY_ABSTRACTION; [line 11]\n " shape="box"] + + + 6 -> 5 ; +5 [label="5: Exit zero_ref \n " color=yellow style=filled] + + +4 [label="4: Start zero_ref\nFormals: p:int &\nLocals: \n DECLARE_LOCALS(&return); [line 11]\n " color=yellow style=filled] + + + 4 -> 6 ; +3 [label="3: BinaryOperatorStmt: Assign \n n$0=*&p:int * [line 10]\n *n$0:int =0 [line 10]\n REMOVE_TEMPS(n$0); [line 10]\n NULLIFY(&p,false); [line 10]\n APPLY_ABSTRACTION; [line 10]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit zero_ptr \n " color=yellow style=filled] + + +1 [label="1: Start zero_ptr\nFormals: p:int *\nLocals: \n DECLARE_LOCALS(&return); [line 10]\n " color=yellow style=filled] + + + 1 -> 3 ; +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/unbox.cpp b/infer/tests/codetoanalyze/cpp/frontend/reference/unbox.cpp new file mode 100644 index 000000000..e9f8ebcc3 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/unbox.cpp @@ -0,0 +1,34 @@ +/* +* 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. +*/ + +int fun_p(int *p) { return *p;} +int fun_v(int p) { return p;} +int fun_r(int &p) { return p;} + +// cfgs should look similar for unbox_ref and unbox_ptr + +// test conversions from int& to {int*, int, int&) +void unbox_ref() { + int a = 3; + int& r = a; + + fun_p(&r); + fun_v(r); + fun_r(r); +} + +// test conversions from int* to {int*, int, int&) +void unbox_ptr() { + int a = 3; + int *p = &a; + + fun_p(p); + fun_v(*p); + fun_r(*p); +} diff --git a/infer/tests/codetoanalyze/cpp/frontend/reference/unbox.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/reference/unbox.cpp.dot new file mode 100644 index 000000000..0b58dafa6 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/frontend/reference/unbox.cpp.dot @@ -0,0 +1,89 @@ +digraph iCFG { +23 [label="23: DeclStmt \n *&a:int =3 [line 28]\n " shape="box"] + + + 23 -> 22 ; +22 [label="22: DeclStmt \n *&p:int *=&a [line 29]\n " shape="box"] + + + 22 -> 21 ; +21 [label="21: Call _fun_fun_p \n n$5=*&p:int * [line 31]\n n$6=_fun_fun_p(n$5:int *) [line 31]\n REMOVE_TEMPS(n$5,n$6); [line 31]\n " shape="box"] + + + 21 -> 20 ; +20 [label="20: Call _fun_fun_v \n n$2=*&p:int * [line 32]\n n$3=*n$2:int [line 32]\n n$4=_fun_fun_v(n$3:int ) [line 32]\n REMOVE_TEMPS(n$2,n$3,n$4); [line 32]\n " shape="box"] + + + 20 -> 19 ; +19 [label="19: Call _fun_fun_r \n n$0=*&p:int * [line 33]\n n$1=_fun_fun_r(n$0:int ) [line 33]\n REMOVE_TEMPS(n$0,n$1); [line 33]\n NULLIFY(&p,false); [line 33]\n NULLIFY(&a,false); [line 33]\n APPLY_ABSTRACTION; [line 33]\n " shape="box"] + + + 19 -> 18 ; +18 [label="18: Exit unbox_ptr \n " color=yellow style=filled] + + +17 [label="17: Start unbox_ptr\nFormals: \nLocals: p:int * a:int \n DECLARE_LOCALS(&return,&p,&a); [line 27]\n NULLIFY(&p,false); [line 27]\n " color=yellow style=filled] + + + 17 -> 23 ; +16 [label="16: DeclStmt \n *&a:int =3 [line 18]\n " shape="box"] + + + 16 -> 15 ; +15 [label="15: DeclStmt \n *&r:int =&a [line 19]\n " shape="box"] + + + 15 -> 14 ; +14 [label="14: Call _fun_fun_p \n n$5=*&r:int & [line 21]\n n$6=_fun_fun_p(n$5:int *) [line 21]\n REMOVE_TEMPS(n$5,n$6); [line 21]\n " shape="box"] + + + 14 -> 13 ; +13 [label="13: Call _fun_fun_v \n n$2=*&r:int & [line 22]\n n$3=*n$2:int [line 22]\n n$4=_fun_fun_v(n$3:int ) [line 22]\n REMOVE_TEMPS(n$2,n$3,n$4); [line 22]\n " shape="box"] + + + 13 -> 12 ; +12 [label="12: Call _fun_fun_r \n n$0=*&r:int & [line 23]\n n$1=_fun_fun_r(n$0:int ) [line 23]\n REMOVE_TEMPS(n$0,n$1); [line 23]\n NULLIFY(&r,false); [line 23]\n NULLIFY(&a,false); [line 23]\n APPLY_ABSTRACTION; [line 23]\n " shape="box"] + + + 12 -> 11 ; +11 [label="11: Exit unbox_ref \n " color=yellow style=filled] + + +10 [label="10: Start unbox_ref\nFormals: \nLocals: r:int & a:int \n DECLARE_LOCALS(&return,&r,&a); [line 17]\n NULLIFY(&r,false); [line 17]\n " color=yellow style=filled] + + + 10 -> 16 ; +9 [label="9: Return Stmt \n n$0=*&p:int & [line 12]\n n$1=*n$0:int [line 12]\n *&return:int =n$1 [line 12]\n REMOVE_TEMPS(n$0,n$1); [line 12]\n NULLIFY(&p,false); [line 12]\n APPLY_ABSTRACTION; [line 12]\n " shape="box"] + + + 9 -> 8 ; +8 [label="8: Exit fun_r \n " color=yellow style=filled] + + +7 [label="7: Start fun_r\nFormals: p:int &\nLocals: \n DECLARE_LOCALS(&return); [line 12]\n " color=yellow style=filled] + + + 7 -> 9 ; +6 [label="6: Return Stmt \n n$0=*&p:int [line 11]\n *&return:int =n$0 [line 11]\n REMOVE_TEMPS(n$0); [line 11]\n NULLIFY(&p,false); [line 11]\n APPLY_ABSTRACTION; [line 11]\n " shape="box"] + + + 6 -> 5 ; +5 [label="5: Exit fun_v \n " color=yellow style=filled] + + +4 [label="4: Start fun_v\nFormals: p:int \nLocals: \n DECLARE_LOCALS(&return); [line 11]\n " color=yellow style=filled] + + + 4 -> 6 ; +3 [label="3: Return Stmt \n n$0=*&p:int * [line 10]\n n$1=*n$0:int [line 10]\n *&return:int =n$1 [line 10]\n REMOVE_TEMPS(n$0,n$1); [line 10]\n NULLIFY(&p,false); [line 10]\n APPLY_ABSTRACTION; [line 10]\n " shape="box"] + + + 3 -> 2 ; +2 [label="2: Exit fun_p \n " color=yellow style=filled] + + +1 [label="1: Start fun_p\nFormals: p:int *\nLocals: \n DECLARE_LOCALS(&return); [line 10]\n " color=yellow style=filled] + + + 1 -> 3 ; +} diff --git a/infer/tests/endtoend/cpp/ReferenceStructTest.java b/infer/tests/endtoend/cpp/ReferenceStructTest.java new file mode 100644 index 000000000..c24845860 --- /dev/null +++ b/infer/tests/endtoend/cpp/ReferenceStructTest.java @@ -0,0 +1,70 @@ +/* +* 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.cpp; + +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 ReferenceStructTest { + + public static final String FILE = + "infer/tests/codetoanalyze/cpp/frontend/reference/reference_struct_e2e.cpp"; + + private static ImmutableList inferCmd; + + public static final String DIVIDE_BY_ZERO = "DIVIDE_BY_ZERO"; + + @ClassRule + public static DebuggableTemporaryFolder folder = + new DebuggableTemporaryFolder(); + + @BeforeClass + public static void runInfer() throws InterruptedException, IOException { + inferCmd = InferRunner.createCPPInferCommand(folder, FILE); + } + + @Test + public void whenInferRunsOnDiv0MethodsErrorIsFound() + throws InterruptedException, IOException, InferException { + InferResults inferResults = InferRunner.runInferCPP(inferCmd); + String[] procedures = { + "method_div0_ptr", + "field_div0_ptr", + "get_global_ptr_div0_method", + "get_global_ptr_div0_field", + "method_div0_ref", + "field_div0_ref", + "get_global_ref_div0_method", + "get_global_ref_div0_field" + }; + assertThat( + "Results should contain the expected divide by zero", + inferResults, + containsExactly( + DIVIDE_BY_ZERO, + FILE, + procedures + ) + ); + } +} diff --git a/infer/tests/endtoend/cpp/ReferenceTypeTest.java b/infer/tests/endtoend/cpp/ReferenceTypeTest.java new file mode 100644 index 000000000..de53fb318 --- /dev/null +++ b/infer/tests/endtoend/cpp/ReferenceTypeTest.java @@ -0,0 +1,68 @@ +/* +* 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.cpp; + +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 ReferenceTypeTest { + + public static final String FILE = + "infer/tests/codetoanalyze/cpp/frontend/reference/reference_type_e2e.cpp"; + + private static ImmutableList inferCmd; + + public static final String DIVIDE_BY_ZERO = "DIVIDE_BY_ZERO"; + + @ClassRule + public static DebuggableTemporaryFolder folder = + new DebuggableTemporaryFolder(); + + @BeforeClass + public static void runInfer() throws InterruptedException, IOException { + inferCmd = InferRunner.createCPPInferCommand(folder, FILE); + } + + @Test + public void whenInferRunsOnDiv0MethodsErrorIsFound() + throws InterruptedException, IOException, InferException { + InferResults inferResults = InferRunner.runInferCPP(inferCmd); + String[] procedures = { + "ptr_div0", + "ptr_div0_function", + "ptr_div0_function_temp_var", + "ref_div0", + "ref_div0_function", + "ref_div0_function_temp_var" + }; + assertThat( + "Results should contain the expected divide by zero", + inferResults, + containsExactly( + DIVIDE_BY_ZERO, + FILE, + procedures + ) + ); + } +} diff --git a/infer/tests/frontend/cpp/ReferenceTest.java b/infer/tests/frontend/cpp/ReferenceTest.java new file mode 100644 index 000000000..c0fdb11ed --- /dev/null +++ b/infer/tests/frontend/cpp/ReferenceTest.java @@ -0,0 +1,73 @@ +/* +* 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 frontend.cpp; + +import org.junit.Rule; +import org.junit.Test; + +import java.io.IOException; + +import utils.DebuggableTemporaryFolder; +import utils.InferException; +import utils.ClangFrontendUtils; + +public class ReferenceTest { + + String basePath = "infer/tests/codetoanalyze/cpp/frontend/reference/"; + + @Rule + public DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder(); + + void frontendTest(String fileRelative) throws InterruptedException, IOException, InferException { + ClangFrontendUtils.createAndCompareCppDotFiles(folder, basePath + fileRelative); + } + + @Test + public void testBoxDotFilesMatch() + throws InterruptedException, IOException, InferException { + frontendTest("box.cpp"); + } + + @Test + public void testUnboxDotFilesMatch() + throws InterruptedException, IOException, InferException { + frontendTest("unbox.cpp"); + } + + @Test + public void testInitDotFilesMatch() + throws InterruptedException, IOException, InferException { + frontendTest("init.cpp"); + } + + @Test + public void testMemberAccessDotFilesMatch() + throws InterruptedException, IOException, InferException { + frontendTest("member_access.cpp"); + } + + @Test + public void testMemberAccessFromReturnDotFilesMatch() + throws InterruptedException, IOException, InferException { + frontendTest("member_access_from_return.cpp"); + } + + @Test + public void testReferenceTypeE2EDotFilesMatch() + throws InterruptedException, IOException, InferException { + frontendTest("reference_type_e2e.cpp"); + } + + @Test + public void testReferenceStructE2EDotFilesMatch() + throws InterruptedException, IOException, InferException { + frontendTest("reference_struct_e2e.cpp"); + } +}