Add destructor calls on delete expression

Summary:
public
Add destructor calls on delete expression.
While not the most important, it is the simplest case of adding destructor calls.
This will help us in the future with more complex cases.

Reviewed By: ddino

Differential Revision: D2773483

fb-gh-sync-id: 4df9c73
master
Andrzej Kotulski 9 years ago committed by facebook-github-bot-5
parent a509c9ca7c
commit bd935c2347

@ -421,6 +421,18 @@ struct
Cfg.set_procname_priority context.CContext.cfg pname; Cfg.set_procname_priority context.CContext.cfg pname;
{ pre_trans_result with exps = [method_exp] @ extra_exps } { pre_trans_result with exps = [method_exp] @ extra_exps }
let destructor_deref_trans trans_state pvar_trans_result class_type_ptr =
let open Clang_ast_t in
let destruct_decl_ref_opt = match Ast_utils.get_decl_from_typ_ptr class_type_ptr with
| Some CXXRecordDecl (_, _, _ , _, _, _, _, cxx_record_info)
| Some ClassTemplateSpecializationDecl (_, _, _, _, _, _, _, cxx_record_info) ->
cxx_record_info.xrdi_destructor
| _ -> None in
match destruct_decl_ref_opt with
| Some decl_ref -> method_deref_trans trans_state pvar_trans_result decl_ref
| None -> empty_res_trans
let cxxThisExpr_trans trans_state stmt_info expr_info = let cxxThisExpr_trans trans_state stmt_info expr_info =
let context = trans_state.context in let context = trans_state.context in
let sil_loc = CLocation.get_sil_location stmt_info context in let sil_loc = CLocation.get_sil_location stmt_info context in
@ -774,6 +786,13 @@ struct
Sil.Tvoid Sil.Tvoid
| _ -> assert false | _ -> assert false
and cxx_destructor_call_trans trans_state si this_res_trans class_type_ptr =
let trans_state_pri = PriorityNode.try_claim_priority_node trans_state si in
let res_trans_callee = destructor_deref_trans trans_state this_res_trans class_type_ptr in
if res_trans_callee.exps <> [] then
cxx_method_construct_call_trans trans_state_pri res_trans_callee [] si Sil.Tvoid
else empty_res_trans
and objCMessageExpr_trans_special_cases trans_state si obj_c_message_expr_info stmt_list and objCMessageExpr_trans_special_cases trans_state si obj_c_message_expr_info stmt_list
expr_info method_type trans_state_pri sil_loc act_params = expr_info method_type trans_state_pri sil_loc act_params =
let context = trans_state.context in let context = trans_state.context in
@ -1759,7 +1778,7 @@ struct
(* 1. Handle __new_array *) (* 1. Handle __new_array *)
(* 2. Handle initialization values *) (* 2. Handle initialization values *)
and cxxDeleteExpr_trans trans_state stmt_info stmt_list expr_info = and cxxDeleteExpr_trans trans_state stmt_info stmt_list expr_info delete_expr_info =
let context = trans_state.context in let context = trans_state.context in
let sil_loc = CLocation.get_sil_location stmt_info context in let sil_loc = CLocation.get_sil_location stmt_info context in
let fname = SymExec.ModelBuiltins.__delete in let fname = SymExec.ModelBuiltins.__delete in
@ -1769,10 +1788,19 @@ struct
let result_trans_param = exec_with_self_exception instruction trans_state_param param in let result_trans_param = exec_with_self_exception instruction trans_state_param param in
let exp = extract_exp_from_list result_trans_param.exps let exp = extract_exp_from_list result_trans_param.exps
"WARNING: There should be one expression to delete. \n" in "WARNING: There should be one expression to delete. \n" in
let deleted_type = delete_expr_info.Clang_ast_t.xdei_destroyed_type in
(* create stmt_info with new pointer so that destructor call doesn't create a node *)
let destruct_stmt_info = { stmt_info with
Clang_ast_t.si_pointer = Ast_utils.get_fresh_pointer () } in
(* use empty_res_trans to avoid ending up with same instruction twice *)
(* otherwise it would happen due to structutre of all_res_trans *)
let this_res_trans_destruct = { empty_res_trans with exps = result_trans_param.exps } in
let destruct_res_trans = cxx_destructor_call_trans trans_state_pri destruct_stmt_info
this_res_trans_destruct deleted_type in
(* function is void *) (* function is void *)
let call_instr = Sil.Call ([], (Sil.Const (Sil.Cfun fname)), [exp], sil_loc, Sil.cf_default) in let call_instr = Sil.Call ([], (Sil.Const (Sil.Cfun fname)), [exp], sil_loc, Sil.cf_default) in
let call_res_trans = { empty_res_trans with instrs = [call_instr] } in let call_res_trans = { empty_res_trans with instrs = [call_instr] } in
let all_res_trans = [ result_trans_param; call_res_trans] in let all_res_trans = [ result_trans_param; destruct_res_trans; call_res_trans] in
let res_trans = PriorityNode.compute_results_to_parent trans_state_pri sil_loc let res_trans = PriorityNode.compute_results_to_parent trans_state_pri sil_loc
"Call delete" stmt_info all_res_trans in "Call delete" stmt_info all_res_trans in
{ res_trans with exps = [] } { res_trans with exps = [] }
@ -2005,8 +2033,8 @@ struct
assert false) assert false)
| CXXNewExpr (stmt_info, stmt_list, expr_info, _) -> | CXXNewExpr (stmt_info, stmt_list, expr_info, _) ->
cxxNewExpr_trans trans_state stmt_info expr_info cxxNewExpr_trans trans_state stmt_info expr_info
| CXXDeleteExpr (stmt_info, stmt_list, expr_info, _) -> | CXXDeleteExpr (stmt_info, stmt_list, expr_info, delete_expr_info) ->
cxxDeleteExpr_trans trans_state stmt_info stmt_list expr_info cxxDeleteExpr_trans trans_state stmt_info stmt_list expr_info delete_expr_info
| MaterializeTemporaryExpr (stmt_info, stmt_list, expr_info, _) -> | MaterializeTemporaryExpr (stmt_info, stmt_list, expr_info, _) ->
materializeTemporaryExpr_trans trans_state stmt_info stmt_list expr_info materializeTemporaryExpr_trans trans_state stmt_info stmt_list expr_info
| s -> (Printing.log_stats | s -> (Printing.log_stats

@ -0,0 +1,20 @@
/*
* 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 {
~X() {}
};
void deleteX(X *x) {
delete x;
}
void deleteInt(int *x) {
delete x;
}

@ -0,0 +1,31 @@
digraph iCFG {
8 [label="8: Call delete \n n$0=*&x:int * [line 19]\n _fun___delete(n$0:int *) [line 19]\n REMOVE_TEMPS(n$0); [line 19]\n NULLIFY(&x,false); [line 19]\n APPLY_ABSTRACTION; [line 19]\n " shape="box"]
8 -> 7 ;
7 [label="7: Exit deleteInt \n " color=yellow style=filled]
6 [label="6: Start deleteInt\nFormals: x:int *\nLocals: \n DECLARE_LOCALS(&return); [line 18]\n " color=yellow style=filled]
6 -> 8 ;
5 [label="5: Call delete \n n$0=*&x:class X * [line 15]\n _fun_X_~X(n$0:class X *) [line 15]\n _fun___delete(n$0:class X *) [line 15]\n REMOVE_TEMPS(n$0); [line 15]\n NULLIFY(&x,false); [line 15]\n APPLY_ABSTRACTION; [line 15]\n " shape="box"]
5 -> 4 ;
4 [label="4: Exit deleteX \n " color=yellow style=filled]
3 [label="3: Start deleteX\nFormals: x:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 14]\n " color=yellow style=filled]
3 -> 5 ;
2 [label="2: Exit X_~X \n " color=yellow style=filled]
1 [label="1: Start X_~X\nFormals: this:class X *\nLocals: \n DECLARE_LOCALS(&return); [line 11]\n NULLIFY(&this,false); [line 11]\n " color=yellow style=filled]
1 -> 2 ;
}

@ -35,4 +35,10 @@ public class DestructorsTest {
frontendTest("simple_decl.cpp"); frontendTest("simple_decl.cpp");
} }
@Test
public void testCallOnDeleteDotFilesMatch()
throws InterruptedException, IOException, InferException {
frontendTest("call_on_delete.cpp");
}
} }

Loading…
Cancel
Save