Skip to content

Commit 70c193d

Browse files
jvillardfacebook-github-bot
authored andcommitted
[pulse] manage path contexts (no use yet)
Summary: Keep track of which conditionals the current instruction is being affected by: ``` if (x) { // (1) a = 1; // affected by (1) if (y) { // (2) b = 1; // affected by (1) and (2) } } c = 1; // affected by no conditionals ``` Reviewed By: skcho Differential Revision: D31479142 fbshipit-source-id: b2e749ba0
1 parent 5793d58 commit 70c193d

File tree

7 files changed

+79
-34
lines changed

7 files changed

+79
-34
lines changed

infer/src/pulse/Pulse.ml

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -398,18 +398,6 @@ module PulseTransferFunctions = struct
398398
astates
399399
in
400400
(PulseReport.report_results tenv proc_desc err_log loc result, path, astate_n)
401-
| Prune (condition, loc, _is_then_branch, _if_kind) ->
402-
let results =
403-
(let<*> astate = PulseOperations.prune path loc ~condition astate in
404-
if PulseArithmetic.is_unsat_cheap astate then
405-
(* [condition] is known to be unsatisfiable: prune path *)
406-
[]
407-
else
408-
(* [condition] is true or unknown value: go into the branch *)
409-
[Ok (ContinueProgram astate)] )
410-
|> PulseReport.report_exec_results tenv proc_desc err_log loc
411-
in
412-
(results, path, astate_n)
413401
| Call (ret, call_exp, actuals, loc, call_flags) ->
414402
let astates =
415403
dispatch_call analysis_data path ret call_exp actuals loc call_flags astate
@@ -419,6 +407,40 @@ module PulseTransferFunctions = struct
419407
, path
420408
, PulseNonDisjunctiveOperations.add_copies loc call_exp actuals call_flags astates
421409
astate_n )
410+
| Prune (condition, loc, is_then_branch, if_kind) ->
411+
let result, path =
412+
match PulseOperations.prune path loc ~condition astate with
413+
| Ok (astate, hist) ->
414+
let path =
415+
if Sil.is_terminated_if_kind if_kind then
416+
let hist =
417+
ValueHistory.ConditionPassed
418+
{if_kind; is_then_branch; location= loc; timestamp}
419+
:: hist
420+
in
421+
{path with conditions= hist :: path.conditions}
422+
else path
423+
in
424+
(Ok astate, path)
425+
| Error _ as err ->
426+
(err, path)
427+
in
428+
let results =
429+
let<*> astate = result in
430+
if PulseArithmetic.is_unsat_cheap astate then
431+
(* [condition] is known to be unsatisfiable: prune path *)
432+
[]
433+
else
434+
(* [condition] is true or unknown value: go into the branch *)
435+
[Ok (ContinueProgram astate)]
436+
in
437+
(PulseReport.report_exec_results tenv proc_desc err_log loc results, path, astate_n)
438+
| Metadata EndBranches ->
439+
(* We assume that terminated conditions are well-parenthesised, hence an [EndBranches]
440+
instruction terminates the most recently seen terminated conditional. The empty case
441+
shouldn't happen but let's not crash by the fault of possible errors in frontends. *)
442+
let path = {path with conditions= List.tl path.conditions |> Option.value ~default:[]} in
443+
([ContinueProgram astate], path, astate_n)
422444
| Metadata (ExitScope (vars, location)) ->
423445
let remove_vars vars astates =
424446
List.map astates ~f:(fun (exec_state : ExecutionDomain.t) ->
@@ -458,7 +480,6 @@ module PulseTransferFunctions = struct
458480
| Metadata
459481
( Abstract _
460482
| CatchEntry _
461-
| EndBranches
462483
| Nullify _
463484
| Skip
464485
| TryEntry _

infer/src/pulse/PulseOperations.ml

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -278,22 +278,33 @@ let eval path mode location exp0 astate =
278278
eval path mode exp0 astate
279279

280280

281-
let eval_to_operand path mode location exp astate =
281+
let eval_to_operand path location exp astate =
282282
match (exp : Exp.t) with
283283
| Const (Cint i) ->
284-
Ok (astate, PulseArithmetic.LiteralOperand i)
284+
Ok (astate, PulseArithmetic.LiteralOperand i, [])
285285
| exp ->
286-
let+ astate, (value, _) = eval path mode location exp astate in
287-
(astate, PulseArithmetic.AbstractValueOperand value)
286+
let+ astate, (value, hist) = eval path Read location exp astate in
287+
(astate, PulseArithmetic.AbstractValueOperand value, hist)
288288

289289

290290
let prune path location ~condition astate =
291291
let rec prune_aux ~negated exp astate =
292292
match (exp : Exp.t) with
293293
| BinOp (bop, exp_lhs, exp_rhs) ->
294-
let* astate, lhs_op = eval_to_operand path Read location exp_lhs astate in
295-
let* astate, rhs_op = eval_to_operand path Read location exp_rhs astate in
296-
PulseArithmetic.prune_binop ~negated bop lhs_op rhs_op astate
294+
let* astate, lhs_op, lhs_hist = eval_to_operand path location exp_lhs astate in
295+
let* astate, rhs_op, rhs_hist = eval_to_operand path location exp_rhs astate in
296+
let+ astate = PulseArithmetic.prune_binop ~negated bop lhs_op rhs_op astate in
297+
let hist =
298+
match (lhs_hist, rhs_hist) with
299+
| [], hist | hist, [] ->
300+
(* if one history is empty then just propagate the other one (which could also be
301+
empty) *)
302+
hist
303+
| _ ->
304+
(* TODO: merge histories *)
305+
lhs_hist
306+
in
307+
(astate, hist)
297308
| UnOp (LNot, exp', _) ->
298309
prune_aux ~negated:(not negated) exp' astate
299310
| exp ->

infer/src/pulse/PulseOperations.mli

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ val eval_structure_isl :
117117
(** Similar to eval but apply to data structures and ISL abduction. Return a list of abduced states
118118
(ISLOk and ISLErs); The boolean indicates whether it is data structures or not. *)
119119

120-
val prune : PathContext.t -> Location.t -> condition:Exp.t -> t -> t AccessResult.t
120+
val prune :
121+
PathContext.t -> Location.t -> condition:Exp.t -> t -> (t * ValueHistory.t) AccessResult.t
121122

122123
val eval_deref :
123124
PathContext.t

infer/src/pulse/PulsePathContext.ml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,22 @@ open! IStd
99
module F = Format
1010
open PulseBasicInterface
1111

12-
type t = {timestamp: Timestamp.t} [@@deriving compare, equal]
12+
type t = {conditions: ValueHistory.t list; timestamp: Timestamp.t} [@@deriving compare, equal]
1313

1414
(** path contexts is metadata that do not contribute to the semantics *)
1515
let leq ~lhs:_ ~rhs:_ = true
1616

1717
(** see [leq] *)
1818
let equal_fast _ _ = true
1919

20-
let pp fmt ({timestamp} [@warning "+9"]) = F.fprintf fmt "timestamp= %a" Timestamp.pp timestamp
20+
let pp fmt ({conditions; timestamp} [@warning "+9"]) =
21+
let pp_condition fmt hist =
22+
if Config.debug_level_analysis >= 3 then F.fprintf fmt "[%a]" ValueHistory.pp hist
23+
in
24+
F.fprintf fmt "conditions= [%a]@;timestamp= %a" (Pp.seq ~sep:";" pp_condition) conditions
25+
Timestamp.pp timestamp
2126

22-
let initial = {timestamp= Timestamp.t0}
2327

24-
let post_exec_instr {timestamp} = {timestamp= Timestamp.incr timestamp}
28+
let initial = {conditions= []; timestamp= Timestamp.t0}
29+
30+
let post_exec_instr {conditions; timestamp} = {conditions; timestamp= Timestamp.incr timestamp}

infer/src/pulse/PulsePathContext.mli

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@ open! IStd
99
module F = Format
1010
open PulseBasicInterface
1111

12-
type t = {timestamp: Timestamp.t (** step number in an intra-procedural analysis *)}
12+
type t =
13+
{ conditions: ValueHistory.t list
14+
(** Each history represents a conditional that is affecting the path currently, with the
15+
most recent conditional first. The idea is to add these histories to the histories of
16+
all variables and memory locations modified while under the influence of these
17+
conditionals. *)
18+
; timestamp: Timestamp.t (** step number in an intra-procedural analysis *) }
1319
[@@deriving compare, equal]
1420

1521
val leq : lhs:t -> rhs:t -> bool

infer/src/pulse/PulseValueHistory.ml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ type event =
2020
; mode: CapturedVar.capture_mode
2121
; location: Location.t
2222
; timestamp: Timestamp.t }
23-
| Conditional of
24-
{is_then_branch: bool; if_kind: Sil.if_kind; location: Location.t; timestamp: Timestamp.t}
23+
| ConditionPassed of
24+
{if_kind: Sil.if_kind; is_then_branch: bool; location: Location.t; timestamp: Timestamp.t}
2525
| CppTemporaryCreated of Location.t * Timestamp.t
2626
| FormalDeclared of Pvar.t * Location.t * Timestamp.t
2727
| Invalidated of PulseInvalidation.t * Location.t * Timestamp.t
@@ -38,7 +38,7 @@ let location_of_event = function
3838
| Assignment (location, _)
3939
| Call {location}
4040
| Capture {location}
41-
| Conditional {location}
41+
| ConditionPassed {location}
4242
| CppTemporaryCreated (location, _)
4343
| FormalDeclared (_, location, _)
4444
| Invalidated (_, location, _)
@@ -58,7 +58,7 @@ let rec iter_event event ~f =
5858
| Allocation _
5959
| Assignment _
6060
| Capture _
61-
| Conditional _
61+
| ConditionPassed _
6262
| CppTemporaryCreated _
6363
| FormalDeclared _
6464
| Invalidated _
@@ -93,11 +93,11 @@ let pp_event_no_location fmt event =
9393
F.pp_print_string fmt "assigned"
9494
| Call {f} ->
9595
F.fprintf fmt "in call to %a" CallEvent.pp f
96-
| Capture {captured_as; mode; location= _} ->
96+
| Capture {captured_as; mode} ->
9797
F.fprintf fmt "value captured %s as `%a`"
9898
(CapturedVar.string_of_capture_mode mode)
9999
Pvar.pp_value_non_verbose captured_as
100-
| Conditional {is_then_branch; if_kind; location= _} ->
100+
| ConditionPassed {is_then_branch; if_kind} ->
101101
F.fprintf fmt "expression in %a condition is %b" Sil.pp_if_kind if_kind is_then_branch
102102
| CppTemporaryCreated _ ->
103103
F.pp_print_string fmt "C++ temporary created"

infer/src/pulse/PulseValueHistory.mli

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ type event =
1818
; mode: CapturedVar.capture_mode
1919
; location: Location.t
2020
; timestamp: Timestamp.t }
21-
| Conditional of
22-
{is_then_branch: bool; if_kind: Sil.if_kind; location: Location.t; timestamp: Timestamp.t}
21+
| ConditionPassed of
22+
{if_kind: Sil.if_kind; is_then_branch: bool; location: Location.t; timestamp: Timestamp.t}
2323
| CppTemporaryCreated of Location.t * Timestamp.t
2424
| FormalDeclared of Pvar.t * Location.t * Timestamp.t
2525
| Invalidated of PulseInvalidation.t * Location.t * Timestamp.t

0 commit comments

Comments
 (0)