[log] Even better exception reraising

Summary:
`reraise` was error-prone when one forgot to save the backtrace between where the exception is caught and where it is reraised.
If any exception was raised (even caught) in between, the printed backtrace would be the one of the last exception thrown and it would be very confusing.

This diff kills `reraise` and introduces `reraise_after exn ~f` and `reraise_if exn ~f` to be used right after catching the exception.

Also turned some of them to the common pattern `try_finally ~f ~finally`.

Reviewed By: jvillard

Differential Revision: D5911244

fbshipit-source-id: 9883d1e
master
Mehdi Bouaziz 7 years ago committed by Facebook Github Bot
parent f05cc6385c
commit bb15aba766

@ -1564,10 +1564,11 @@ let sigma_partial_join tenv mode (sigma1: Prop.sigma) (sigma2: Prop.sigma)
CheckJoin.init mode sigma1 sigma2 ; CheckJoin.init mode sigma1 sigma2 ;
let lost_little = CheckJoin.lost_little in let lost_little = CheckJoin.lost_little in
let s1, s2, s3 = sigma_partial_join' tenv mode [] sigma1 sigma2 in let s1, s2, s3 = sigma_partial_join' tenv mode [] sigma1 sigma2 in
try Utils.try_finally
if Rename.check lost_little then ( CheckJoin.final () ; (s1, s2, s3) ) ~f:(fun () ->
else ( L.d_strln "failed Rename.check" ; CheckJoin.final () ; raise Sil.JoinFail ) if Rename.check lost_little then (s1, s2, s3)
with exn -> CheckJoin.final () ; reraise exn else ( L.d_strln "failed Rename.check" ; raise Sil.JoinFail ))
~finally:CheckJoin.final
let rec sigma_partial_meet' tenv (sigma_acc: Prop.sigma) (sigma1_in: Prop.sigma) let rec sigma_partial_meet' tenv (sigma_acc: Prop.sigma) (sigma1_in: Prop.sigma)
(sigma2_in: Prop.sigma) : Prop.sigma = (sigma2_in: Prop.sigma) : Prop.sigma =
@ -1806,13 +1807,9 @@ let prop_partial_meet tenv p1 p2 =
FreshVarExp.init () ; FreshVarExp.init () ;
Todo.init () ; Todo.init () ;
try try
let res = eprop_partial_meet tenv p1 p2 in Utils.try_finally ~f:(fun () -> Some (eprop_partial_meet tenv p1 p2)) ~finally:(fun () ->
Rename.final () ; FreshVarExp.final () ; Todo.final () ; Some res Rename.final () ; FreshVarExp.final () ; Todo.final () )
with exn -> with Sil.JoinFail -> None
Rename.final () ;
FreshVarExp.final () ;
Todo.final () ;
match exn with Sil.JoinFail -> None | _ -> reraise exn
let eprop_partial_join' tenv mode (ep1: Prop.exposed Prop.t) (ep2: Prop.exposed Prop.t) let eprop_partial_join' tenv mode (ep1: Prop.exposed Prop.t) (ep2: Prop.exposed Prop.t)
: Prop.normal Prop.t = : Prop.normal Prop.t =
@ -1914,21 +1911,15 @@ let prop_partial_join pname tenv mode p1 p2 =
FreshVarExp.init () ; FreshVarExp.init () ;
Todo.init () ; Todo.init () ;
try try
let p1', p2' = footprint_partial_join' tenv p1 p2 in Utils.try_finally
let rename_footprint = Rename.reset () in ~f:(fun () ->
Todo.reset rename_footprint ; let p1', p2' = footprint_partial_join' tenv p1 p2 in
let res = Some (eprop_partial_join' tenv mode (Prop.expose p1') (Prop.expose p2')) in let rename_footprint = Rename.reset () in
if !Config.footprint then JoinState.set_footprint false ; Todo.reset rename_footprint ;
Rename.final () ; let res = eprop_partial_join' tenv mode (Prop.expose p1') (Prop.expose p2') in
FreshVarExp.final () ; if !Config.footprint then JoinState.set_footprint false ;
Todo.final () ; Some res) ~finally:(fun () -> Rename.final () ; FreshVarExp.final () ; Todo.final () )
res with Sil.JoinFail -> None )
with exn ->
Rename.final () ;
FreshVarExp.final () ;
Todo.final () ;
if !Config.footprint then JoinState.set_footprint false ;
match exn with Sil.JoinFail -> None | _ -> reraise exn )
| Some _ | Some _
-> res_by_implication_only -> res_by_implication_only
@ -1937,10 +1928,8 @@ let eprop_partial_join tenv mode (ep1: Prop.exposed Prop.t) (ep2: Prop.exposed P
Rename.init () ; Rename.init () ;
FreshVarExp.init () ; FreshVarExp.init () ;
Todo.init () ; Todo.init () ;
try Utils.try_finally ~f:(fun () -> eprop_partial_join' tenv mode ep1 ep2) ~finally:(fun () ->
let res = eprop_partial_join' tenv mode ep1 ep2 in Rename.final () ; FreshVarExp.final () ; Todo.final () )
Rename.final () ; FreshVarExp.final () ; Todo.final () ; res
with exn -> Rename.final () ; FreshVarExp.final () ; Todo.final () ; reraise exn
(** {2 Join and Meet for Propset} *) (** {2 Join and Meet for Propset} *)

@ -443,10 +443,10 @@ let forward_tabulate tenv proc_cfg wl =
L.d_decrease_indent 1 ; L.d_decrease_indent 1 ;
L.d_ln () L.d_ln ()
with exn -> with exn ->
let backtrace = Caml.Printexc.get_raw_backtrace () in reraise_if exn ~f:(fun () -> not !Config.footprint || not (Exceptions.handle_exception exn)) ;
if Exceptions.handle_exception exn && !Config.footprint then ( handle_exn exn ;
handle_exn exn ; L.d_decrease_indent 1 ; L.d_ln () ) L.d_decrease_indent 1 ;
else reraise ~backtrace exn L.d_ln ()
in in
let do_node curr_node pathset_todo session handle_exn = let do_node curr_node pathset_todo session handle_exn =
check_prop_size pathset_todo ; check_prop_size pathset_todo ;
@ -473,13 +473,11 @@ let forward_tabulate tenv proc_cfg wl =
if !handle_exn_called then Printer.force_delayed_prints () ; if !handle_exn_called then Printer.force_delayed_prints () ;
do_after_node curr_node do_after_node curr_node
with exn -> with exn ->
let backtrace = Caml.Printexc.get_raw_backtrace () in reraise_if exn ~f:(fun () -> not (Exceptions.handle_exception exn)) ;
if Exceptions.handle_exception exn then ( handle_exn_node curr_node exn ;
handle_exn_node curr_node exn ; Printer.force_delayed_prints () ;
Printer.force_delayed_prints () ; do_after_node curr_node ;
do_after_node curr_node ; if not !Config.footprint then raise RE_EXE_ERROR
if not !Config.footprint then raise RE_EXE_ERROR )
else reraise ~backtrace exn
in in
while not (Worklist.is_empty wl) do while not (Worklist.is_empty wl) do
let curr_node = Worklist.remove wl in let curr_node = Worklist.remove wl in

@ -147,19 +147,17 @@ let run_proc_analysis analyze_proc curr_pdesc callee_pdesc =
let final_summary = postprocess summary in let final_summary = postprocess summary in
restore_global_state old_state ; final_summary restore_global_state old_state ; final_summary
with exn -> with exn ->
restore_global_state old_state ; reraise_if exn ~f:(fun () -> restore_global_state old_state ; not Config.keep_going) ;
if Config.keep_going then ( L.internal_error "@\nERROR RUNNING BACKEND: %a %s@\n@\nBACK TRACE@\n%s@?" Typ.Procname.pp
L.internal_error "@\nERROR RUNNING BACKEND: %a %s@\n@\nBACK TRACE@\n%s@?" Typ.Procname.pp callee_pname (Exn.to_string exn) (Printexc.get_backtrace ()) ;
callee_pname (Exn.to_string exn) (Printexc.get_backtrace ()) ; match exn with
match exn with | SymOp.Analysis_failure_exe kind
| SymOp.Analysis_failure_exe kind -> (* in production mode, log the timeout/crash and continue with the summary we had before
-> (* in production mode, log the timeout/crash and continue with the summary we had before the failure occurred *)
the failure occurred *) log_error_and_continue exn initial_summary kind
log_error_and_continue exn initial_summary kind | _
| _ -> (* this happens with assert false or some other unrecognized exception *)
-> (* this happens with assert false or some other unrecognized exception *) log_error_and_continue exn initial_summary (FKcrash (Exn.to_string exn))
log_error_and_continue exn initial_summary (FKcrash (Exn.to_string exn)) )
else reraise exn
let analyze_proc_desc curr_pdesc callee_pdesc : Specs.summary option = let analyze_proc_desc curr_pdesc callee_pdesc : Specs.summary option =
let callee_pname = Procdesc.get_proc_name callee_pdesc in let callee_pname = Procdesc.get_proc_name callee_pdesc in

@ -17,7 +17,7 @@ module F = Format
let decrease_indent_when_exception thunk = let decrease_indent_when_exception thunk =
try thunk () try thunk ()
with exn when SymOp.exn_not_failure exn -> L.d_decrease_indent 1 ; reraise exn with exn when SymOp.exn_not_failure exn -> reraise_after exn ~f:(fun () -> L.d_decrease_indent 1)
let compute_max_from_nonempty_int_list l = uw (List.max_elt ~cmp:IntLit.compare_value l) let compute_max_from_nonempty_int_list l = uw (List.max_elt ~cmp:IntLit.compare_value l)

@ -1401,16 +1401,14 @@ and instrs ?(mask_errors= false) tenv pdesc instrs ppl =
L.d_ln () ; L.d_ln () ;
try sym_exec tenv pdesc instr p path try sym_exec tenv pdesc instr p path
with exn -> with exn ->
let backtrace = Caml.Printexc.get_raw_backtrace () in reraise_if exn ~f:(fun () -> not mask_errors || not (SymOp.exn_not_failure exn)) ;
if SymOp.exn_not_failure exn && mask_errors then let error = Exceptions.recognize_exception exn in
let error = Exceptions.recognize_exception exn in let loc =
let loc = match error.ml_loc with Some ml_loc -> "at " ^ L.ml_loc_to_string ml_loc | None -> ""
match error.ml_loc with Some ml_loc -> "at " ^ L.ml_loc_to_string ml_loc | None -> "" in
in L.d_warning ("Generated Instruction Failed with: " ^ error.name.IssueType.unique_id ^ loc) ;
L.d_warning ("Generated Instruction Failed with: " ^ error.name.IssueType.unique_id ^ loc) ; L.d_ln () ;
L.d_ln () ; [(p, path)]
[(p, path)]
else reraise ~backtrace exn
in in
let f plist instr = List.concat_map ~f:(exe_instr instr) plist in let f plist instr = List.concat_map ~f:(exe_instr instr) plist in
List.fold ~f ~init:ppl instrs List.fold ~f ~init:ppl instrs
@ -1606,14 +1604,13 @@ and check_variadic_sentinel ?(fails_on_nil= false) n_formals (sentinel, null_pos
let load_instr = Sil.Load (tmp_id_deref, lexp, typ, loc) in let load_instr = Sil.Load (tmp_id_deref, lexp, typ, loc) in
try instrs tenv pdesc [load_instr] result try instrs tenv pdesc [load_instr] result
with e when SymOp.exn_not_failure e -> with e when SymOp.exn_not_failure e ->
if not fails_on_nil then reraise_if e ~f:(fun () -> fails_on_nil) ;
let deref_str = Localise.deref_str_nil_argument_in_variadic_method proc_name nargs i in let deref_str = Localise.deref_str_nil_argument_in_variadic_method proc_name nargs i in
let err_desc = let err_desc =
Errdesc.explain_dereference tenv ~use_buckets:true ~is_premature_nil:true deref_str prop_ Errdesc.explain_dereference tenv ~use_buckets:true ~is_premature_nil:true deref_str prop_
loc loc
in in
raise (Exceptions.Premature_nil_termination (err_desc, __POS__)) raise (Exceptions.Premature_nil_termination (err_desc, __POS__))
else reraise e
in in
(* fold_left reverses the arguments back so that we report an *) (* fold_left reverses the arguments back so that we report an *)
(* error on the first premature nil argument *) (* error on the first premature nil argument *)
@ -1804,11 +1801,10 @@ and sym_exec_wrapper handle_exn tenv proc_cfg instr ((prop: Prop.normal Prop.t),
State.mark_instr_ok () ; State.mark_instr_ok () ;
Paths.PathSet.from_renamed_list results Paths.PathSet.from_renamed_list results
with exn -> with exn ->
let backtrace = Caml.Printexc.get_raw_backtrace () in reraise_if exn ~f:(fun () -> not !Config.footprint || not (Exceptions.handle_exception exn)) ;
if Exceptions.handle_exception exn && !Config.footprint then ( handle_exn exn ;
handle_exn exn ; (* calls State.mark_instr_fail *) (* calls State.mark_instr_fail *)
Paths.PathSet.empty ) Paths.PathSet.empty
else reraise ~backtrace exn
(** {2 Lifted Abstract Transfer Functions} *) (** {2 Lifted Abstract Transfer Functions} *)

@ -99,11 +99,11 @@ let exe_timeout f x =
Option.iter (SymOp.get_timeout_seconds ()) ~f:set_alarm ; Option.iter (SymOp.get_timeout_seconds ()) ~f:set_alarm ;
SymOp.set_alarm () SymOp.set_alarm ()
in in
try suspend_existing_timeout_and_start_new_one () ; f x ; resume_previous_timeout () ; None with try
| SymOp.Analysis_failure_exe kind Utils.try_finally
-> resume_previous_timeout () ; ~f:(fun () -> suspend_existing_timeout_and_start_new_one () ; f x ; None)
L.progressbar_timeout_event kind ; ~finally:resume_previous_timeout
Errdesc.warning_err (State.get_loc ()) "TIMEOUT: %a@." SymOp.pp_failure_kind kind ; with SymOp.Analysis_failure_exe kind ->
Some kind L.progressbar_timeout_event kind ;
| exe Errdesc.warning_err (State.get_loc ()) "TIMEOUT: %a@." SymOp.pp_failure_kind kind ;
-> resume_previous_timeout () ; reraise exe Some kind

@ -2412,11 +2412,11 @@ let specs_library =
let set_reference_and_call_function reference value f x = let set_reference_and_call_function reference value f x =
let saved = !reference in let saved = !reference in
let restore () = reference := saved in let restore () = reference := saved in
try Utils.try_finally
reference := value ; ~f:(fun () ->
let res = f x in reference := value ;
restore () ; res f x)
with exn -> restore () ; reraise exn ~finally:restore
(** Current Objective-C Automatic Reference Counting (ARC) mode *) (** Current Objective-C Automatic Reference Counting (ARC) mode *)
let arc_mode = ref false let arc_mode = ref false

@ -28,22 +28,18 @@ let try_finally ?(fail_early= false) f g =
| r | r
-> g () ; r -> g () ; r
| exception (Analysis_failure_exe _ as f_exn) | exception (Analysis_failure_exe _ as f_exn)
-> let backtrace = Caml.Printexc.get_raw_backtrace () in -> reraise_after f_exn ~f:(fun () ->
( if not fail_early then if not fail_early then
try g () try g ()
with _ -> () (* swallow in favor of the original exception *) ) ; with _ -> (* swallow in favor of the original exception *) () )
reraise ~backtrace f_exn
| exception f_exn | exception f_exn
-> let f_backtrace = Caml.Printexc.get_raw_backtrace () in -> reraise_after f_exn ~f:(fun () ->
match g () with try g ()
| () with
-> reraise ~backtrace:f_backtrace f_exn | g_exn
| exception (Analysis_failure_exe _ as g_exn) when (* do not swallow Analysis_failure_exe thrown from g *)
-> reraise g_exn match g_exn with Analysis_failure_exe _ -> false | _ -> true
| exception _ -> () )
-> reraise ~backtrace:f_backtrace f_exn
let finally_try g f = try_finally f g
let pp_failure_kind fmt = function let pp_failure_kind fmt = function
| FKtimeout | FKtimeout

@ -73,7 +73,4 @@ val try_finally : ?fail_early:bool -> (unit -> 'a) -> (unit -> unit) -> 'a
return reasonably quickly. [~fail_early=true] can be passed to skip executing [g ()] when [f return reasonably quickly. [~fail_early=true] can be passed to skip executing [g ()] when [f
()] raises a [Analysis_failure_exe] exception. *) ()] raises a [Analysis_failure_exe] exception. *)
val finally_try : (unit -> unit) -> (unit -> 'a) -> 'a
(** [finally_try g f] is equivalent to [try_finally f g]. *)
val pp_failure_kind : Format.formatter -> failure_kind -> unit val pp_failure_kind : Format.formatter -> failure_kind -> unit

@ -165,29 +165,32 @@ let read_json_file path =
try Ok (Yojson.Basic.from_file path) try Ok (Yojson.Basic.from_file path)
with Sys_error msg | Yojson.Json_error msg -> Error msg with Sys_error msg | Yojson.Json_error msg -> Error msg
let do_finally f g = let do_finally ~f ~finally =
let res = let res =
try f () try f ()
with exc -> with exc ->
let backtrace = Caml.Printexc.get_raw_backtrace () in reraise_after exc ~f:(fun () ->
( try g () |> ignore try finally () |> ignore
with _ -> () (* swallow in favor of the original exception *) ) ; with _ -> (* swallow in favor of the original exception *) () )
reraise ~backtrace exc
in in
let res' = g () in let res' = finally () in
(res, res') (res, res')
let try_finally ~f ~finally =
let res, () = do_finally ~f ~finally in
res
let with_file_in file ~f = let with_file_in file ~f =
let ic = In_channel.create file in let ic = In_channel.create file in
let f () = f ic in let f () = f ic in
let g () = In_channel.close ic in let finally () = In_channel.close ic in
do_finally f g |> fst try_finally ~f ~finally
let with_file_out file ~f = let with_file_out file ~f =
let oc = Out_channel.create file in let oc = Out_channel.create file in
let f () = f oc in let f () = f oc in
let g () = Out_channel.close oc in let finally () = Out_channel.close oc in
do_finally f g |> fst try_finally ~f ~finally
let write_json_to_file destfile json = let write_json_to_file destfile json =
with_file_out destfile ~f:(fun oc -> Yojson.Basic.pretty_to_channel oc json) with_file_out destfile ~f:(fun oc -> Yojson.Basic.pretty_to_channel oc json)
@ -199,8 +202,8 @@ let consume_in chan_in =
let with_process_in command read = let with_process_in command read =
let chan = Unix.open_process_in command in let chan = Unix.open_process_in command in
let f () = read chan in let f () = read chan in
let g () = consume_in chan ; Unix.close_process_in chan in let finally () = consume_in chan ; Unix.close_process_in chan in
do_finally f g do_finally ~f ~finally
let shell_escape_command cmd = let shell_escape_command cmd =
let escape arg = let escape arg =

@ -94,3 +94,6 @@ val write_file_with_locking : ?delete:bool -> f:(Out_channel.t -> unit) -> strin
val rmtree : string -> unit val rmtree : string -> unit
(** [rmtree path] removes [path] and, if [path] is a directory, recursively removes its contents *) (** [rmtree path] removes [path] and, if [path] is a directory, recursively removes its contents *)
val try_finally : f:(unit -> 'a) -> finally:(unit -> unit) -> 'a
(** Calls [f] then [finally] even if [f] raised an exception. The original exception is reraised afterwards. *)

@ -93,9 +93,8 @@ let run_clang_frontend ast_source =
let run_and_validate_clang_frontend ast_source = let run_and_validate_clang_frontend ast_source =
try run_clang_frontend ast_source try run_clang_frontend ast_source
with exc -> with exc ->
if not Config.keep_going then reraise exc reraise_if exc ~f:(fun () -> not Config.keep_going) ;
else L.internal_error "ERROR RUNNING CAPTURE: %a@\n%s@\n" Exn.pp exc (Printexc.get_backtrace ())
L.internal_error "ERROR RUNNING CAPTURE: %a@\n%s@\n" Exn.pp exc (Printexc.get_backtrace ())
let run_clang clang_command read = let run_clang clang_command read =
let exit_with_error exit_code = let exit_with_error exit_code =

@ -59,27 +59,25 @@ let compile compiler build_prog build_args =
let shell_cmd = Utils.shell_escape_command cmd in let shell_cmd = Utils.shell_escape_command cmd in
let shell_cmd_redirected = Printf.sprintf "%s 2>'%s'" shell_cmd verbose_out_file in let shell_cmd_redirected = Printf.sprintf "%s 2>'%s'" shell_cmd verbose_out_file in
L.(debug Capture Quiet) "Trying to execute: %s@." shell_cmd_redirected ; L.(debug Capture Quiet) "Trying to execute: %s@." shell_cmd_redirected ;
let error_k_or_fail err_msg = match Utils.with_process_in shell_cmd_redirected In_channel.input_all with
match (error_k, err_msg) with | log, Error err -> (
| Some k, `UnixError (err, log) match error_k with
| Some k
-> L.(debug Capture Quiet) -> L.(debug Capture Quiet)
"*** Failed: %s!@\n%s@." (Unix.Exit_or_signal.to_string_hum (Error err)) log ; "*** Failed: %s!@\n%s@." (Unix.Exit_or_signal.to_string_hum (Error err)) log ;
k () k ()
| Some k, `ExceptionError exn | None
-> L.(debug Capture Quiet) "*** Failed: %a!@\n" Exn.pp exn ; k ()
| None, `UnixError (err, log)
-> let verbose_errlog = Utils.with_file_in verbose_out_file ~f:In_channel.input_all in -> let verbose_errlog = Utils.with_file_in verbose_out_file ~f:In_channel.input_all in
L.(die UserError) L.(die UserError)
"@\n*** Failed to execute compilation command: %s@\n*** Command: %s@\n*** Output:@\n%s%s@\n*** Infer needs a working compilation command to run.@." "@\n*** Failed to execute compilation command: %s@\n*** Command: %s@\n*** Output:@\n%s%s@\n*** Infer needs a working compilation command to run.@."
(Unix.Exit_or_signal.to_string_hum (Error err)) shell_cmd log verbose_errlog (Unix.Exit_or_signal.to_string_hum (Error err)) shell_cmd log verbose_errlog )
| None, `ExceptionError exn
-> reraise exn
in
match Utils.with_process_in shell_cmd_redirected In_channel.input_all with
| log, Error err
-> error_k_or_fail (`UnixError (err, log))
| exception exn | exception exn
-> error_k_or_fail (`ExceptionError exn) -> reraise_if exn ~f:(fun () ->
match error_k with
| Some k
-> L.(debug Capture Quiet) "*** Failed: %a!@\n" Exn.pp exn ; k () ; false
| None
-> true )
| log, Ok () | log, Ok ()
-> L.(debug Capture Quiet) "*** Success. Logs:@\n%s" log -> L.(debug Capture Quiet) "*** Success. Logs:@\n%s" log
in in

@ -63,12 +63,17 @@ module PVariant = struct
let ( = ) (v1: [> ]) (v2: [> ]) = Polymorphic_compare.( = ) v1 v2 let ( = ) (v1: [> ]) (v2: [> ]) = Polymorphic_compare.( = ) v1 v2
end end
let reraise ?backtrace:backtrace0 exn = (** Reraise the exception after doing f. Always reraise immediately after catching the exception, otherwise the backtrace can be wrong *)
let backtrace = let reraise_after ~f exn =
match backtrace0 with Some bt -> bt | None -> Caml.Printexc.get_raw_backtrace () let backtrace = Caml.Printexc.get_raw_backtrace () in
in let () = f () in
Caml.Printexc.raise_with_backtrace exn backtrace Caml.Printexc.raise_with_backtrace exn backtrace
(** Reraise the exception if f returns true. Always reraise immediately after catching the exception, otherwise the backtrace can be wrong *)
let reraise_if ~f exn =
let backtrace = Caml.Printexc.get_raw_backtrace () in
if f () then Caml.Printexc.raise_with_backtrace exn backtrace
let failwith _ : [`use_Logging_die_instead] = assert false let failwith _ : [`use_Logging_die_instead] = assert false
let failwithf _ : [`use_Logging_die_instead] = assert false let failwithf _ : [`use_Logging_die_instead] = assert false

@ -202,7 +202,9 @@ let compute_source_icfg linereader classes program tenv source_basename package_
{JContext.cg= Cg.create source_file; JContext.cfg= Cfg.create_cfg (); JContext.tenv= tenv} {JContext.cg= Cg.create source_file; JContext.cfg= Cfg.create_cfg (); JContext.tenv= tenv}
in in
let select test procedure cn node = let select test procedure cn node =
if test node then try procedure cn node with Bir.Subroutine -> () | e -> reraise e if test node then
try procedure cn node
with Bir.Subroutine -> ()
in in
let () = let () =
JBasics.ClassMap.iter JBasics.ClassMap.iter
@ -216,9 +218,6 @@ let compute_class_icfg source_file linereader program tenv node =
let icfg = let icfg =
{JContext.cg= Cg.create source_file; JContext.cfg= Cfg.create_cfg (); JContext.tenv= tenv} {JContext.cg= Cg.create source_file; JContext.cfg= Cfg.create_cfg (); JContext.tenv= tenv}
in in
( try create_icfg source_file linereader program icfg (Javalib.get_name node) node with ( try create_icfg source_file linereader program icfg (Javalib.get_name node) node
| Bir.Subroutine with Bir.Subroutine -> () ) ;
-> ()
| e
-> reraise e ) ;
(icfg.JContext.cg, icfg.JContext.cfg) (icfg.JContext.cg, icfg.JContext.cfg)

Loading…
Cancel
Save