Summary: The `Utils` module has another version of try-finally than can swallow exceptions from the restart scheduler. This diff fixes that, but has to also fix the dependency cycle introduced between `SymOp` and `Utils`. This is done by extracting the exception handling from `SymOp` into a new base module `Exception`. Reviewed By: jvillard Differential Revision: D28930082 fbshipit-source-id: 7894d8c89master
parent
85b8ad463c
commit
d5d9a9369a
@ -0,0 +1,57 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
|
||||
open! IStd
|
||||
module F = Format
|
||||
|
||||
type failure_kind =
|
||||
| FKtimeout (** max time exceeded *)
|
||||
| FKsymops_timeout of int (** max symop's exceeded *)
|
||||
| FKrecursion_timeout of int (** max recursion level exceeded *)
|
||||
| FKcrash of string (** uncaught exception or failed assertion *)
|
||||
|
||||
(** failure that prevented biabduction analysis from finishing *)
|
||||
exception Analysis_failure_exe of failure_kind
|
||||
|
||||
let exn_not_failure = function
|
||||
| Analysis_failure_exe _ | RestartSchedulerException.ProcnameAlreadyLocked _ ->
|
||||
false
|
||||
| _ ->
|
||||
true
|
||||
|
||||
|
||||
let try_finally ~f ~finally =
|
||||
match f () with
|
||||
| r ->
|
||||
finally () ;
|
||||
r
|
||||
| exception (Analysis_failure_exe _ as f_exn) ->
|
||||
IExn.reraise_after f_exn ~f:(fun () ->
|
||||
try finally ()
|
||||
with finally_exn when RestartSchedulerException.is_not_restart_exception finally_exn ->
|
||||
(* swallow in favor of the original exception unless it's the restart scheduler exception *)
|
||||
() )
|
||||
| exception f_exn when RestartSchedulerException.is_not_restart_exception f_exn ->
|
||||
IExn.reraise_after f_exn ~f:(fun () ->
|
||||
try finally ()
|
||||
with
|
||||
| finally_exn
|
||||
when (* do not swallow Analysis_failure_exe or restart exception thrown from finally *)
|
||||
exn_not_failure finally_exn
|
||||
->
|
||||
() )
|
||||
|
||||
|
||||
let pp_failure_kind fmt = function
|
||||
| FKtimeout ->
|
||||
F.pp_print_string fmt "TIMEOUT"
|
||||
| FKsymops_timeout symops ->
|
||||
F.fprintf fmt "SYMOPS TIMEOUT (%d)" symops
|
||||
| FKrecursion_timeout level ->
|
||||
F.fprintf fmt "RECURSION TIMEOUT (%d)" level
|
||||
| FKcrash msg ->
|
||||
F.fprintf fmt "CRASH (%s)" msg
|
@ -0,0 +1,30 @@
|
||||
(*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*)
|
||||
|
||||
(** The restart scheduler and biabduction use exceptions for control flow (restarts/timeouts
|
||||
respectively). Functions here abstract away the semantics of when an exception can be ignored. *)
|
||||
|
||||
open! IStd
|
||||
|
||||
(** types of biabduction failure due to timeouts *)
|
||||
type failure_kind =
|
||||
| FKtimeout (** max time exceeded *)
|
||||
| FKsymops_timeout of int (** max symop's exceeded *)
|
||||
| FKrecursion_timeout of int (** max recursion level exceeded *)
|
||||
| FKcrash of string (** uncaught exception or failed assertion *)
|
||||
|
||||
val pp_failure_kind : Format.formatter -> failure_kind -> unit
|
||||
|
||||
(** Timeout exception *)
|
||||
exception Analysis_failure_exe of failure_kind
|
||||
|
||||
val exn_not_failure : exn -> bool
|
||||
(** check that the exception is not a biabduction timeout or restart scheduler exception *)
|
||||
|
||||
val try_finally : f:(unit -> 'a) -> finally:(unit -> unit) -> 'a
|
||||
(** [try_finally ~f ~finally] executes [f] and then [finally] even if [f] raises an exception.
|
||||
Biabduction timeouts and restart scheduler exceptions are handled as necessary. *)
|
Loading…
Reference in new issue