From 5ed2016899b44c36069f8b7294e526cc4735f015 Mon Sep 17 00:00:00 2001 From: Sam Blackshear Date: Mon, 14 May 2018 13:05:06 -0700 Subject: [PATCH] [clang] basic support for exceptional control-flow Summary: This diff: - translates C++ `catch` blocks - adds an exceptional control-flow edge from the end of a `try` block to the beginning of a `catch` block This obviously doesn't reflect the way exceptions actually work, but I think it is better than what we have now. For one thing, we'll see/translate code inside `catch` blocks, which were opaque before. If Clang analyses don't want this behavior, they can simply use `ProcCfg.Normal` (which, up until this diff, behaved identically to `ProcCfg.Exceptional`. In the future, we can extend `trans_state` to track blocks that might throw an exception, and have each of these blocks transition to `catch` instead. Reviewed By: jvillard Differential Revision: D7814521 fbshipit-source-id: 67b86a6 --- infer/src/IR/Procdesc.ml | 2 + infer/src/IR/Procdesc.mli | 2 + infer/src/clang/cTrans.ml | 49 +++++- .../cpp/liveness/dead_stores.cpp | 123 ++++++++++++++ .../codetoanalyze/cpp/liveness/issues.exp | 4 +- .../cpp/shared/exceptions/Exceptions.cpp | 48 ++++++ .../cpp/shared/exceptions/Exceptions.cpp.dot | 157 ++++++++++++++++-- 7 files changed, 366 insertions(+), 19 deletions(-) diff --git a/infer/src/IR/Procdesc.ml b/infer/src/IR/Procdesc.ml index 7c05e50ff..641a528b8 100644 --- a/infer/src/IR/Procdesc.ml +++ b/infer/src/IR/Procdesc.ml @@ -332,6 +332,8 @@ let append_locals pdesc new_locals = (pdesc.attributes).locals <- pdesc.attributes.locals @ new_locals +let set_succs_exn_only (node: Node.t) exn = node.exn <- exn + (** Set the successor nodes and exception nodes, and build predecessor links *) let set_succs_exn_base (node: Node.t) succs exn = node.succs <- succs ; diff --git a/infer/src/IR/Procdesc.mli b/infer/src/IR/Procdesc.mli index 35c602d54..b89b1dd0d 100644 --- a/infer/src/IR/Procdesc.mli +++ b/infer/src/IR/Procdesc.mli @@ -190,6 +190,8 @@ val iter_nodes : (Node.t -> unit) -> t -> unit val iter_slope_range : (Node.t -> unit) -> Node.t -> Node.t -> unit (** iterate between two nodes or until we reach a branching structure *) +val set_succs_exn_only : Node.t -> Node.t list -> unit + val node_set_succs_exn : t -> Node.t -> Node.t list -> Node.t list -> unit (** Set the successor nodes and exception nodes, and build predecessor links *) diff --git a/infer/src/clang/cTrans.ml b/infer/src/clang/cTrans.ml index 6ef668dd0..af5f20fca 100644 --- a/infer/src/clang/cTrans.ml +++ b/infer/src/clang/cTrans.ml @@ -1939,6 +1939,43 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s instruction trans_state' stmt + and tryStmt_trans trans_state stmts = + let open Clang_ast_t in + let translate_catch catch_root_nodes_acc = function + | CXXCatchStmt (catch_stmt_info, catch_body_stmts, _) -> + let catch_trans_result = + compoundStmt_trans trans_state catch_stmt_info catch_body_stmts + in + (* no risk of duplicates because two catch blocks should never have the same root nodes + (they have to be in different syntactic locations, after all!) *) + catch_trans_result.control.root_nodes @ catch_root_nodes_acc + | _ -> + assert false + in + match stmts with + | try_body_stmt :: catch_stmts -> + let try_trans_result = instruction trans_state try_body_stmt in + let catch_start_nodes = List.fold catch_stmts ~f:translate_catch ~init:[] in + (* add catch block as exceptional successor to end of try block. not ideal, but we will at + least reach the code in the catch block this way *) + (* TODO (T28898377): instead, we should extend trans_state with a list of maybe-throwing + blocks, and add transitions from those to the catch block instead *) + let try_control = try_trans_result.control in + let try_ends = + if List.is_empty try_control.leaf_nodes then + (* try ends in return; transition from beginning instead *) + try_control.root_nodes + else try_control.leaf_nodes + in + List.iter + ~f:(fun try_end -> Procdesc.set_succs_exn_only try_end catch_start_nodes) + try_ends ; + try_trans_result + | _ -> + (* try should always have a catch statement *) + assert false + + and loop_instruction trans_state loop_kind stmt_info = let outer_continuation = trans_state.continuation in let context = trans_state.context in @@ -3323,16 +3360,16 @@ module CTrans_funct (F : CModule_type.CFrontend) : CModule_type.CTranslation = s compoundStmt_trans trans_state stmt_info stmts | ObjCAtTryStmt (stmt_info, stmts) -> compoundStmt_trans trans_state stmt_info stmts - | CXXTryStmt (stmt_info, stmts) -> - L.(debug Capture Medium) - "@\n!!!!WARNING: found statement %s. @\nTranslation need to be improved.... @\n" - (Clang_ast_proj.get_stmt_kind_string instr) ; - compoundStmt_trans trans_state stmt_info stmts + | CXXTryStmt (_, try_stmts) -> + tryStmt_trans trans_state try_stmts + | CXXCatchStmt _ -> + (* should by handled by try statement *) + assert false | ObjCAtThrowStmt (stmt_info, stmts) | CXXThrowExpr (stmt_info, stmts, _) -> objc_cxx_throw_trans trans_state stmt_info stmts | ObjCAtFinallyStmt (stmt_info, stmts) -> compoundStmt_trans trans_state stmt_info stmts - | ObjCAtCatchStmt (stmt_info, _, _) | CXXCatchStmt (stmt_info, _, _) -> + | ObjCAtCatchStmt (stmt_info, _, _) -> compoundStmt_trans trans_state stmt_info [] | PredefinedExpr (_, _, expr_info, _) -> stringLiteral_trans trans_state expr_info "" diff --git a/infer/tests/codetoanalyze/cpp/liveness/dead_stores.cpp b/infer/tests/codetoanalyze/cpp/liveness/dead_stores.cpp index 99c3d141f..84f37abb2 100644 --- a/infer/tests/codetoanalyze/cpp/liveness/dead_stores.cpp +++ b/infer/tests/codetoanalyze/cpp/liveness/dead_stores.cpp @@ -7,8 +7,10 @@ * of patent rights can be found in the PATENTS file in the same directory. */ +#include #include #include +#include #include namespace infer { @@ -358,4 +360,125 @@ void dead_lock_guard_ok() { std::lock_guard lock(my_mutex); } void dead_unique_lock_ok() { std::unique_lock lock(my_mutex); } +extern int maybe_throw(); + +class Exceptions { + + int read_in_catch1_ok() { + int i = 1; + try { + throw std::runtime_error("error"); + } catch (...) { + return i; + } + return 0; + } + + int read_in_catch_explicit_throw_ok() { + int i = 1; + try { + maybe_throw(); + } catch (...) { + return i; + } + return 0; + } + + int dead_in_catch_bad() { + try { + throw std::runtime_error("error"); + } catch (...) { + int i = 1; + } + return 0; + } + + int FN_unreachable_catch_bad() { + int i = 1; + try { + } catch (...) { + return i; + } + return 0; + } + + int multiple_catches_ok(bool b) { + int i = 1; + int j = 2; + try { + if (b) { + throw std::length_error("error"); + } else { + throw std::range_error("error"); + } + } catch (std::length_error& msg) { + return i; + } catch (std::range_error& msg) { + return j; + } + return 0; + } + + void dont_throw() {} + + int FN_harder_unreachable_catch_bad() { + int i = 1; + try { + dont_throw(); + } catch (...) { + return i; + } + return 0; + } + + // currently, the only transition to the catch block is at the end of the try + // block + int FP_read_in_catch_tricky_ok(bool b1, bool b2) { + int i = 1; + try { + if (b1) { + throw std::runtime_error("error"); + } + i = 2; + if (b2) { + throw std::runtime_error("error"); + } + } catch (...) { + return i; + } + return 0; + } + + int return_in_try1_ok() { + bool b; + + try { + maybe_throw(); + return 3; + } catch (const char* msg) { + b = true; + } + + if (b) { + return 2; + } + return 3; + } + + int return_in_try2_ok() { + bool b; + + try { + return maybe_throw(); + } catch (const char* msg) { + b = true; + } + + if (b) { + return 2; + } + return 3; + } +}; + } diff --git a/infer/tests/codetoanalyze/cpp/liveness/issues.exp b/infer/tests/codetoanalyze/cpp/liveness/issues.exp index 88d8eaee1..d8de3eaaa 100644 --- a/infer/tests/codetoanalyze/cpp/liveness/issues.exp +++ b/infer/tests/codetoanalyze/cpp/liveness/issues.exp @@ -1,3 +1,5 @@ +codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::Exceptions_FP_read_in_catch_tricky_ok, 1, DEAD_STORE, ERROR, [Write of unused value] +codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::Exceptions_dead_in_catch_bad, 4, DEAD_STORE, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::FP_assign_array_tricky_ok, 3, DEAD_STORE, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::capture_by_value_bad, 3, DEAD_STORE, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::dead_pointer_bad, 2, DEAD_STORE, ERROR, [Write of unused value] @@ -8,7 +10,7 @@ codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::dead_then_live_bad, 1, codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::easy_bad, 0, DEAD_STORE, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::init_capture_no_call_bad, 1, DEAD_STORE, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::init_capture_reassign_bad, 1, DEAD_STORE, ERROR, [Write of unused value] -codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::lambda_bad::lambda_dead_stores.cpp:147:11_operator(), 1, DEAD_STORE, ERROR, [Write of unused value] +codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::lambda_bad::lambda_dead_stores.cpp:149:11_operator(), 1, DEAD_STORE, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus1_bad, 2, DEAD_STORE, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus2_bad, 2, DEAD_STORE, ERROR, [Write of unused value] codetoanalyze/cpp/liveness/dead_stores.cpp, dead_stores::plus_plus3_bad, 2, DEAD_STORE, ERROR, [Write of unused value] diff --git a/infer/tests/codetoanalyze/cpp/shared/exceptions/Exceptions.cpp b/infer/tests/codetoanalyze/cpp/shared/exceptions/Exceptions.cpp index a562dce45..e05c742db 100644 --- a/infer/tests/codetoanalyze/cpp/shared/exceptions/Exceptions.cpp +++ b/infer/tests/codetoanalyze/cpp/shared/exceptions/Exceptions.cpp @@ -7,6 +7,9 @@ * of patent rights can be found in the PATENTS file in the same directory. */ +#include +#include + int deref(int* p) { if (p == 0) { throw "Null pointer!"; @@ -23,6 +26,51 @@ int deref_null(int* p) { int call_deref_with_null() { deref_null(nullptr); } +void basic_throw_ok() { throw std::runtime_error("throwing!"); } + +int dead_deref_null_after_throw_ok() { + int* i = nullptr; + throw std::runtime_error("throwing!"); + return *i; +} + +int FN_deref_null_in_catch_bad() { + int* i = nullptr; + try { + throw std::runtime_error("error"); + } catch (...) { + return *i; + } + return 0; +} + +int FN_deref_null_after_catch_bad(int* i) { + try { + *i = 2; + throw std::runtime_error("error"); + } catch (...) { + i = nullptr; + } + return *i; +} + +int FN_multiple_catches_bad(bool b) { + int* i = nullptr; + int* j = nullptr; + try { + if (b) { + throw std::length_error("error"); + } else { + throw std::range_error("error"); + } + } catch (std::length_error& msg) { + return *i; + } catch (std::range_error& msg) { + return *j; + } + return 0; +} + int main() { try { return deref(0); diff --git a/infer/tests/codetoanalyze/cpp/shared/exceptions/Exceptions.cpp.dot b/infer/tests/codetoanalyze/cpp/shared/exceptions/Exceptions.cpp.dot index faba2686b..faccf6d6e 100644 --- a/infer/tests/codetoanalyze/cpp/shared/exceptions/Exceptions.cpp.dot +++ b/infer/tests/codetoanalyze/cpp/shared/exceptions/Exceptions.cpp.dot @@ -1,24 +1,152 @@ /* @generated */ digraph cfg { -"call_deref_with_null#4611966425999531792.6346543307e9a799421a89e451b917c2_1" [label="1: Start call_deref_with_null\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 24, column 1]\n " color=yellow style=filled] +"FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_1" [label="1: Start FN_deref_null_after_catch_bad\nFormals: i:int*\nLocals: 0$?%__sil_tmp__temp_construct_n$4:std::runtime_error 0$?%__sil_tmpSIL_materialize_temp__n$5:std::runtime_error const \n DECLARE_LOCALS(&return,&0$?%__sil_tmp__temp_construct_n$4,&0$?%__sil_tmpSIL_materialize_temp__n$5); [line 47, column 1]\n " color=yellow style=filled] + + + "FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_1" -> "FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_5" ; +"FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_2" [label="2: Exit FN_deref_null_after_catch_bad \n " color=yellow style=filled] + + +"FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_3" [label="3: Return Stmt \n n$0=*&i:int* [line 54, column 11]\n n$1=*n$0:int [line 54, column 10]\n *&return:int=n$1 [line 54, column 3]\n " shape="box"] + + + "FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_3" -> "FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_2" ; +"FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_4" [label="4: ObjCCPPThrow \n n$6=_fun_std::runtime_error_runtime_error(&0$?%__sil_tmpSIL_materialize_temp__n$5:std::runtime_error const *,\"error\":char const *) [line 50, column 11]\n n$7=_fun_std::runtime_error_runtime_error(&0$?%__sil_tmp__temp_construct_n$4:std::runtime_error*,&0$?%__sil_tmpSIL_materialize_temp__n$5:std::runtime_error const &) [line 50, column 11]\n n$8=_fun___infer_objc_cpp_throw(&0$?%__sil_tmp__temp_construct_n$4:std::runtime_error) [line 50, column 5]\n " shape="box"] + + + "FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_4" -> "FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_3" ; + "FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_4" -> "FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_6" [color="red" ]; +"FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_5" [label="5: BinaryOperatorStmt: Assign \n n$9=*&i:int* [line 49, column 6]\n *n$9:int=2 [line 49, column 5]\n " shape="box"] + + + "FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_5" -> "FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_4" ; +"FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_6" [label="6: BinaryOperatorStmt: Assign \n *&i:int*=null [line 52, column 5]\n " shape="box"] + + + "FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_6" -> "FN_deref_null_after_catch_bad#4627123003703707696.43441e3badf1bb571cbe770f9d51a51c_3" ; +"FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_1" [label="1: Start FN_deref_null_in_catch_bad\nFormals: \nLocals: 0$?%__sil_tmp__temp_construct_n$2:std::runtime_error 0$?%__sil_tmpSIL_materialize_temp__n$3:std::runtime_error const i:int* \n DECLARE_LOCALS(&return,&0$?%__sil_tmp__temp_construct_n$2,&0$?%__sil_tmpSIL_materialize_temp__n$3,&i); [line 37, column 1]\n " color=yellow style=filled] + + + "FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_1" -> "FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_6" ; +"FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_2" [label="2: Exit FN_deref_null_in_catch_bad \n " color=yellow style=filled] + + +"FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_3" [label="3: Return Stmt \n *&return:int=0 [line 44, column 3]\n " shape="box"] + + + "FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_3" -> "FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_2" ; +"FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_4" [label="4: ObjCCPPThrow \n n$4=_fun_std::runtime_error_runtime_error(&0$?%__sil_tmpSIL_materialize_temp__n$3:std::runtime_error const *,\"error\":char const *) [line 40, column 11]\n n$5=_fun_std::runtime_error_runtime_error(&0$?%__sil_tmp__temp_construct_n$2:std::runtime_error*,&0$?%__sil_tmpSIL_materialize_temp__n$3:std::runtime_error const &) [line 40, column 11]\n n$6=_fun___infer_objc_cpp_throw(&0$?%__sil_tmp__temp_construct_n$2:std::runtime_error) [line 40, column 5]\n " shape="box"] + + + "FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_4" -> "FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_3" ; + "FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_4" -> "FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_5" [color="red" ]; +"FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_5" [label="5: Return Stmt \n n$8=*&i:int* [line 42, column 13]\n n$9=*n$8:int [line 42, column 12]\n *&return:int=n$9 [line 42, column 5]\n " shape="box"] + + + "FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_5" -> "FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_2" ; +"FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_6" [label="6: DeclStmt \n *&i:int*=null [line 38, column 3]\n " shape="box"] + + + "FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_6" -> "FN_deref_null_in_catch_bad#9297890526029657977.c83eec7c9ab8ce2e38ddbc08f8c3dfeb_4" ; +"FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_1" [label="1: Start FN_multiple_catches_bad\nFormals: b:_Bool\nLocals: 0$?%__sil_tmp__temp_construct_n$4:std::length_error 0$?%__sil_tmpSIL_materialize_temp__n$5:std::length_error const 0$?%__sil_tmp__temp_construct_n$10:std::range_error 0$?%__sil_tmpSIL_materialize_temp__n$11:std::range_error const j:int* i:int* \n DECLARE_LOCALS(&return,&0$?%__sil_tmp__temp_construct_n$4,&0$?%__sil_tmpSIL_materialize_temp__n$5,&0$?%__sil_tmp__temp_construct_n$10,&0$?%__sil_tmpSIL_materialize_temp__n$11,&j,&i); [line 57, column 1]\n " color=yellow style=filled] + + + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_1" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_12" ; +"FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_2" [label="2: Exit FN_multiple_catches_bad \n " color=yellow style=filled] + + +"FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_3" [label="3: Return Stmt \n *&return:int=0 [line 71, column 3]\n " shape="box"] + + + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_3" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_2" ; +"FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_4" [label="4: + \n " ] + + + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_4" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_3" ; + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_4" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_10" [color="red" ]; + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_4" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_9" [color="red" ]; +"FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_5" [label="5: Prune (true branch, if) \n n$2=*&b:_Bool [line 61, column 9]\n PRUNE(n$2, true); [line 61, column 9]\n " shape="invhouse"] + + + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_5" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_7" ; +"FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_6" [label="6: Prune (false branch, if) \n n$2=*&b:_Bool [line 61, column 9]\n PRUNE(!n$2, false); [line 61, column 9]\n " shape="invhouse"] + + + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_6" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_8" ; +"FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_7" [label="7: ObjCCPPThrow \n n$6=_fun_std::length_error_length_error(&0$?%__sil_tmpSIL_materialize_temp__n$5:std::length_error const *,\"error\":char const *) [line 62, column 13]\n n$7=_fun_std::length_error_length_error(&0$?%__sil_tmp__temp_construct_n$4:std::length_error*,&0$?%__sil_tmpSIL_materialize_temp__n$5:std::length_error const &) [line 62, column 13]\n n$8=_fun___infer_objc_cpp_throw(&0$?%__sil_tmp__temp_construct_n$4:std::length_error) [line 62, column 7]\n " shape="box"] + + + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_7" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_4" ; +"FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_8" [label="8: ObjCCPPThrow \n n$12=_fun_std::range_error_range_error(&0$?%__sil_tmpSIL_materialize_temp__n$11:std::range_error const *,\"error\":char const *) [line 64, column 13]\n n$13=_fun_std::range_error_range_error(&0$?%__sil_tmp__temp_construct_n$10:std::range_error*,&0$?%__sil_tmpSIL_materialize_temp__n$11:std::range_error const &) [line 64, column 13]\n n$14=_fun___infer_objc_cpp_throw(&0$?%__sil_tmp__temp_construct_n$10:std::range_error) [line 64, column 7]\n " shape="box"] + + + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_8" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_4" ; +"FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_9" [label="9: Return Stmt \n n$17=*&i:int* [line 67, column 13]\n n$18=*n$17:int [line 67, column 12]\n *&return:int=n$18 [line 67, column 5]\n " shape="box"] + + + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_9" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_2" ; +"FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_10" [label="10: Return Stmt \n n$21=*&j:int* [line 69, column 13]\n n$22=*n$21:int [line 69, column 12]\n *&return:int=n$22 [line 69, column 5]\n " shape="box"] + + + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_10" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_2" ; +"FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_11" [label="11: DeclStmt \n *&j:int*=null [line 59, column 3]\n " shape="box"] + + + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_11" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_5" ; + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_11" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_6" ; +"FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_12" [label="12: DeclStmt \n *&i:int*=null [line 58, column 3]\n " shape="box"] + + + "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_12" -> "FN_multiple_catches_bad#4595182522053295670.680a793e449c2d7439ff6441ca69fa98_11" ; +"basic_throw_ok#10529188890980782893.c9e1b8dd080b2621cfca65612331859d_1" [label="1: Start basic_throw_ok\nFormals: \nLocals: 0$?%__sil_tmp__temp_construct_n$1:std::runtime_error 0$?%__sil_tmpSIL_materialize_temp__n$2:std::runtime_error const \n DECLARE_LOCALS(&return,&0$?%__sil_tmp__temp_construct_n$1,&0$?%__sil_tmpSIL_materialize_temp__n$2); [line 29, column 1]\n " color=yellow style=filled] + + + "basic_throw_ok#10529188890980782893.c9e1b8dd080b2621cfca65612331859d_1" -> "basic_throw_ok#10529188890980782893.c9e1b8dd080b2621cfca65612331859d_3" ; +"basic_throw_ok#10529188890980782893.c9e1b8dd080b2621cfca65612331859d_2" [label="2: Exit basic_throw_ok \n " color=yellow style=filled] + + +"basic_throw_ok#10529188890980782893.c9e1b8dd080b2621cfca65612331859d_3" [label="3: ObjCCPPThrow \n n$3=_fun_std::runtime_error_runtime_error(&0$?%__sil_tmpSIL_materialize_temp__n$2:std::runtime_error const *,\"throwing!\":char const *) [line 29, column 31]\n n$4=_fun_std::runtime_error_runtime_error(&0$?%__sil_tmp__temp_construct_n$1:std::runtime_error*,&0$?%__sil_tmpSIL_materialize_temp__n$2:std::runtime_error const &) [line 29, column 31]\n n$5=_fun___infer_objc_cpp_throw(&0$?%__sil_tmp__temp_construct_n$1:std::runtime_error) [line 29, column 25]\n " shape="box"] + + + "basic_throw_ok#10529188890980782893.c9e1b8dd080b2621cfca65612331859d_3" -> "basic_throw_ok#10529188890980782893.c9e1b8dd080b2621cfca65612331859d_2" ; +"call_deref_with_null#4611966425999531792.6346543307e9a799421a89e451b917c2_1" [label="1: Start call_deref_with_null\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 27, column 1]\n " color=yellow style=filled] "call_deref_with_null#4611966425999531792.6346543307e9a799421a89e451b917c2_1" -> "call_deref_with_null#4611966425999531792.6346543307e9a799421a89e451b917c2_3" ; "call_deref_with_null#4611966425999531792.6346543307e9a799421a89e451b917c2_2" [label="2: Exit call_deref_with_null \n " color=yellow style=filled] -"call_deref_with_null#4611966425999531792.6346543307e9a799421a89e451b917c2_3" [label="3: Call _fun_deref_null \n n$1=_fun_deref_null(null:int*) [line 24, column 30]\n " shape="box"] +"call_deref_with_null#4611966425999531792.6346543307e9a799421a89e451b917c2_3" [label="3: Call _fun_deref_null \n n$1=_fun_deref_null(null:int*) [line 27, column 30]\n " shape="box"] "call_deref_with_null#4611966425999531792.6346543307e9a799421a89e451b917c2_3" -> "call_deref_with_null#4611966425999531792.6346543307e9a799421a89e451b917c2_2" ; -"deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_1" [label="1: Start deref\nFormals: p:int*\nLocals: \n DECLARE_LOCALS(&return); [line 10, column 1]\n " color=yellow style=filled] +"dead_deref_null_after_throw_ok#12025371096822526715.42d41c040f3a321bb94f60bf7b55d001_1" [label="1: Start dead_deref_null_after_throw_ok\nFormals: \nLocals: 0$?%__sil_tmp__temp_construct_n$3:std::runtime_error 0$?%__sil_tmpSIL_materialize_temp__n$4:std::runtime_error const i:int* \n DECLARE_LOCALS(&return,&0$?%__sil_tmp__temp_construct_n$3,&0$?%__sil_tmpSIL_materialize_temp__n$4,&i); [line 31, column 1]\n " color=yellow style=filled] + + + "dead_deref_null_after_throw_ok#12025371096822526715.42d41c040f3a321bb94f60bf7b55d001_1" -> "dead_deref_null_after_throw_ok#12025371096822526715.42d41c040f3a321bb94f60bf7b55d001_5" ; +"dead_deref_null_after_throw_ok#12025371096822526715.42d41c040f3a321bb94f60bf7b55d001_2" [label="2: Exit dead_deref_null_after_throw_ok \n " color=yellow style=filled] + + +"dead_deref_null_after_throw_ok#12025371096822526715.42d41c040f3a321bb94f60bf7b55d001_3" [label="3: Return Stmt \n n$0=*&i:int* [line 34, column 11]\n n$1=*n$0:int [line 34, column 10]\n *&return:int=n$1 [line 34, column 3]\n " shape="box"] + + + "dead_deref_null_after_throw_ok#12025371096822526715.42d41c040f3a321bb94f60bf7b55d001_3" -> "dead_deref_null_after_throw_ok#12025371096822526715.42d41c040f3a321bb94f60bf7b55d001_2" ; +"dead_deref_null_after_throw_ok#12025371096822526715.42d41c040f3a321bb94f60bf7b55d001_4" [label="4: ObjCCPPThrow \n n$5=_fun_std::runtime_error_runtime_error(&0$?%__sil_tmpSIL_materialize_temp__n$4:std::runtime_error const *,\"throwing!\":char const *) [line 33, column 9]\n n$6=_fun_std::runtime_error_runtime_error(&0$?%__sil_tmp__temp_construct_n$3:std::runtime_error*,&0$?%__sil_tmpSIL_materialize_temp__n$4:std::runtime_error const &) [line 33, column 9]\n n$7=_fun___infer_objc_cpp_throw(&0$?%__sil_tmp__temp_construct_n$3:std::runtime_error) [line 33, column 3]\n " shape="box"] + + + "dead_deref_null_after_throw_ok#12025371096822526715.42d41c040f3a321bb94f60bf7b55d001_4" -> "dead_deref_null_after_throw_ok#12025371096822526715.42d41c040f3a321bb94f60bf7b55d001_3" ; +"dead_deref_null_after_throw_ok#12025371096822526715.42d41c040f3a321bb94f60bf7b55d001_5" [label="5: DeclStmt \n *&i:int*=null [line 32, column 3]\n " shape="box"] + + + "dead_deref_null_after_throw_ok#12025371096822526715.42d41c040f3a321bb94f60bf7b55d001_5" -> "dead_deref_null_after_throw_ok#12025371096822526715.42d41c040f3a321bb94f60bf7b55d001_4" ; +"deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_1" [label="1: Start deref\nFormals: p:int*\nLocals: \n DECLARE_LOCALS(&return); [line 13, column 1]\n " color=yellow style=filled] "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_1" -> "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_5" ; "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_2" [label="2: Exit deref \n " color=yellow style=filled] -"deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_3" [label="3: Return Stmt \n n$0=*&p:int* [line 14, column 11]\n n$1=*n$0:int [line 14, column 10]\n *&return:int=n$1 [line 14, column 3]\n " shape="box"] +"deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_3" [label="3: Return Stmt \n n$0=*&p:int* [line 17, column 11]\n n$1=*n$0:int [line 17, column 10]\n *&return:int=n$1 [line 17, column 3]\n " shape="box"] "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_3" -> "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_2" ; @@ -26,43 +154,48 @@ digraph cfg { "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_4" -> "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_3" ; -"deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_5" [label="5: BinaryOperatorStmt: EQ \n n$3=*&p:int* [line 11, column 7]\n " shape="box"] +"deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_5" [label="5: BinaryOperatorStmt: EQ \n n$3=*&p:int* [line 14, column 7]\n " shape="box"] "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_5" -> "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_6" ; "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_5" -> "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_7" ; -"deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_6" [label="6: Prune (true branch, if) \n PRUNE((n$3 == null), true); [line 11, column 7]\n " shape="invhouse"] +"deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_6" [label="6: Prune (true branch, if) \n PRUNE((n$3 == null), true); [line 14, column 7]\n " shape="invhouse"] "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_6" -> "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_8" ; -"deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_7" [label="7: Prune (false branch, if) \n PRUNE(!(n$3 == null), false); [line 11, column 7]\n " shape="invhouse"] +"deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_7" [label="7: Prune (false branch, if) \n PRUNE(!(n$3 == null), false); [line 14, column 7]\n " shape="invhouse"] "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_7" -> "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_4" ; -"deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_8" [label="8: ObjCCPPThrow \n n$5=_fun___infer_objc_cpp_throw(\"Null pointer!\":char const *) [line 12, column 5]\n " shape="box"] +"deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_8" [label="8: ObjCCPPThrow \n n$5=_fun___infer_objc_cpp_throw(\"Null pointer!\":char const *) [line 15, column 5]\n " shape="box"] "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_8" -> "deref#13506892413034678690.824465c4193ad2288eb512b1083edab3_4" ; -"deref_null#11536394632240553702.ea4eed042da22ab7ceb619ec1b7f73bb_1" [label="1: Start deref_null\nFormals: p:int*\nLocals: \n DECLARE_LOCALS(&return); [line 17, column 1]\n " color=yellow style=filled] +"deref_null#11536394632240553702.ea4eed042da22ab7ceb619ec1b7f73bb_1" [label="1: Start deref_null\nFormals: p:int*\nLocals: \n DECLARE_LOCALS(&return); [line 20, column 1]\n " color=yellow style=filled] "deref_null#11536394632240553702.ea4eed042da22ab7ceb619ec1b7f73bb_1" -> "deref_null#11536394632240553702.ea4eed042da22ab7ceb619ec1b7f73bb_3" ; "deref_null#11536394632240553702.ea4eed042da22ab7ceb619ec1b7f73bb_2" [label="2: Exit deref_null \n " color=yellow style=filled] -"deref_null#11536394632240553702.ea4eed042da22ab7ceb619ec1b7f73bb_3" [label="3: Return Stmt \n n$4=*&p:int* [line 19, column 13]\n n$5=*n$4:int [line 19, column 12]\n *&return:int=n$5 [line 19, column 5]\n " shape="box"] +"deref_null#11536394632240553702.ea4eed042da22ab7ceb619ec1b7f73bb_3" [label="3: Return Stmt \n n$1=*&p:int* [line 22, column 13]\n n$2=*n$1:int [line 22, column 12]\n *&return:int=n$2 [line 22, column 5]\n " shape="box"] "deref_null#11536394632240553702.ea4eed042da22ab7ceb619ec1b7f73bb_3" -> "deref_null#11536394632240553702.ea4eed042da22ab7ceb619ec1b7f73bb_2" ; -"main.fad58de7366495db4650cfefac2fcd61_1" [label="1: Start main\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 26, column 1]\n " color=yellow style=filled] +"main.fad58de7366495db4650cfefac2fcd61_1" [label="1: Start main\nFormals: \nLocals: \n DECLARE_LOCALS(&return); [line 74, column 1]\n " color=yellow style=filled] "main.fad58de7366495db4650cfefac2fcd61_1" -> "main.fad58de7366495db4650cfefac2fcd61_3" ; "main.fad58de7366495db4650cfefac2fcd61_2" [label="2: Exit main \n " color=yellow style=filled] -"main.fad58de7366495db4650cfefac2fcd61_3" [label="3: Return Stmt \n n$4=_fun_deref(null:int*) [line 28, column 12]\n *&return:int=n$4 [line 28, column 5]\n " shape="box"] +"main.fad58de7366495db4650cfefac2fcd61_3" [label="3: Return Stmt \n n$1=_fun_deref(null:int*) [line 76, column 12]\n *&return:int=n$1 [line 76, column 5]\n " shape="box"] "main.fad58de7366495db4650cfefac2fcd61_3" -> "main.fad58de7366495db4650cfefac2fcd61_2" ; + "main.fad58de7366495db4650cfefac2fcd61_3" -> "main.fad58de7366495db4650cfefac2fcd61_4" [color="red" ]; +"main.fad58de7366495db4650cfefac2fcd61_4" [label="4: Return Stmt \n *&return:int=-1 [line 78, column 5]\n " shape="box"] + + + "main.fad58de7366495db4650cfefac2fcd61_4" -> "main.fad58de7366495db4650cfefac2fcd61_2" ; }