[pulse] stop the analysis when precondition cannot be applied for reasons others than errors

Summary:
If a precondition cannot be applied, it means that this program path
somehow doesn't make sense for the caller and so should be pruned. Right
now we just treat this as skipping over the call instead.

This will become more important when specs start mentioning arithmetic
facts that must be satisfied at the call site. As it is we will only
stop if we discover aliasing in the pre not present at the call site or
vice versa.

Reviewed By: dulmarod

Differential Revision: D18115230

fbshipit-source-id: 4f1c7a583
master
Jules Villard 5 years ago committed by Facebook Github Bot
parent 5508a64d60
commit 36ffe4722b

@ -831,11 +831,11 @@ module PrePost = struct
| exception Aliasing -> | exception Aliasing ->
(* can't make sense of the pre-condition in the current context: give up on that particular (* can't make sense of the pre-condition in the current context: give up on that particular
pre/post pair *) pre/post pair *)
Ok (astate, None) Ok None
| None -> | None ->
(* couldn't apply the pre for some technical reason (as in: not by the fault of the (* couldn't apply the pre for some technical reason (as in: not by the fault of the
programmer as far as we know) *) programmer as far as we know) *)
Ok (astate, None) Ok None
| Some (Error _ as error) -> | Some (Error _ as error) ->
(* error: the function call requires to read some state known to be invalid *) (* error: the function call requires to read some state known to be invalid *)
error error
@ -843,7 +843,7 @@ module PrePost = struct
(* reset [visited] *) (* reset [visited] *)
let call_state = {call_state with visited= AddressSet.empty} in let call_state = {call_state with visited= AddressSet.empty} in
(* apply the postcondition *) (* apply the postcondition *)
Ok (apply_post callee_proc_name call_location pre_post ~formals ~actuals call_state) Ok (Some (apply_post callee_proc_name call_location pre_post ~formals ~actuals call_state))
end end
let extract_pre {pre} = (pre :> BaseDomain.t) let extract_pre {pre} = (pre :> BaseDomain.t)

@ -97,8 +97,9 @@ module PrePost : sig
-> formals:Var.t list -> formals:Var.t list
-> actuals:((AbstractValue.t * ValueHistory.t) * Typ.t) list -> actuals:((AbstractValue.t * ValueHistory.t) * Typ.t) list
-> domain_t -> domain_t
-> (domain_t * (AbstractValue.t * ValueHistory.t) option, Diagnostic.t) result -> ((domain_t * (AbstractValue.t * ValueHistory.t) option) option, Diagnostic.t) result
(** return the abstract state after the call along with an optional return value *) (** return the abstract state after the call along with an optional return value, or [None] if
the precondition could not be satisfied (e.g. some aliasing constraints were not satisfied) *)
end end
val discard_unreachable : t -> t val discard_unreachable : t -> t

@ -371,8 +371,13 @@ let call ~caller_summary call_loc callee_pname ~ret ~actuals astate =
List.fold_result preposts ~init:[] ~f:(fun posts pre_post -> List.fold_result preposts ~init:[] ~f:(fun posts pre_post ->
(* apply all pre/post specs *) (* apply all pre/post specs *)
AbductiveDomain.PrePost.apply callee_pname call_loc pre_post ~formals ~actuals astate AbductiveDomain.PrePost.apply callee_pname call_loc pre_post ~formals ~actuals astate
>>| fun (post, return_val_opt) -> >>| function
let event = ValueHistory.Call {f= Call callee_pname; location= call_loc; in_call= []} in | None ->
(* couldn't apply pre/post pair *) posts
| Some (post, return_val_opt) ->
let event =
ValueHistory.Call {f= Call callee_pname; location= call_loc; in_call= []}
in
let post = let post =
match return_val_opt with match return_val_opt with
| Some (return_val, return_hist) -> | Some (return_val, return_hist) ->

Loading…
Cancel
Save