[topl] Added limits, to avoid high runtimes in corner-cases.

Summary:
Added a topl-max-disjuncts, which is analogous to pulse-max-disjuncts.
Note, however, that the maximum number of states tracked will be the
product of the two limits.

Added also topl-max-conjuncts, which drops Topl states that became too
complex.

Reviewed By: jvillard

Differential Revision: D25240386

fbshipit-source-id: 588c90390
master
Radu Grigore 5 years ago committed by Facebook GitHub Bot
parent 7de9c49a6d
commit 3478a8828f

@ -1951,6 +1951,12 @@ INTERNAL OPTIONS
Activates: Mode for testing, where no headers are translated, and Activates: Mode for testing, where no headers are translated, and
dot files are created (clang only) (Conversely: --no-testing-mode) dot files are created (clang only) (Conversely: --no-testing-mode)
--topl-max-conjuncts int
Stop tracking states that reach have at least int conjuncts
--topl-max-disjuncts int
Under-approximate after int disjunctions in the domain
--topl-properties +path --topl-properties +path
[EXPERIMENTAL] Specify a file containing a temporal property [EXPERIMENTAL] Specify a file containing a temporal property
definition (e.g., jdk.topl). One needs to also select one of the three implementations, by definition (e.g., jdk.topl). One needs to also select one of the three implementations, by

@ -2317,6 +2317,16 @@ and test_filtering =
"List all the files Infer can report on (should be called from the root of the project)" "List all the files Infer can report on (should be called from the root of the project)"
and topl_max_conjuncts =
CLOpt.mk_int ~long:"topl-max-conjuncts" ~default:20
"Stop tracking states that reach have at least $(i,int) conjuncts"
and topl_max_disjuncts =
CLOpt.mk_int ~long:"topl-max-disjuncts" ~default:20
"Under-approximate after $(i,int) disjunctions in the domain"
and topl_properties = and topl_properties =
CLOpt.mk_path_list ~default:[] ~long:"topl-properties" CLOpt.mk_path_list ~default:[] ~long:"topl-properties"
"[EXPERIMENTAL] Specify a file containing a temporal property definition (e.g., jdk.topl).\n\ "[EXPERIMENTAL] Specify a file containing a temporal property definition (e.g., jdk.topl).\n\
@ -3282,6 +3292,10 @@ and testing_mode = !testing_mode
and threadsafe_aliases = !threadsafe_aliases and threadsafe_aliases = !threadsafe_aliases
and topl_max_conjuncts = !topl_max_conjuncts
and topl_max_disjuncts = !topl_max_disjuncts
and topl_properties = !topl_properties and topl_properties = !topl_properties
and trace_error = !trace_error and trace_error = !trace_error

@ -597,6 +597,10 @@ val testing_mode : bool
val threadsafe_aliases : Yojson.Basic.t val threadsafe_aliases : Yojson.Basic.t
val topl_max_conjuncts : int
val topl_max_disjuncts : int
val topl_properties : string list val topl_properties : string list
val trace_error : bool val trace_error : bool

@ -252,7 +252,43 @@ let drop_infeasible path_condition state =
List.filter ~f state List.filter ~f state
let normalize_memory memory = List.sort ~compare:[%compare: register * value] memory
let normalize_configuration {vertex; memory} = {vertex; memory= normalize_memory memory}
let normalize_pruned pruned = List.dedup_and_sort ~compare:compare_predicate pruned
let normalize_simple_state {pre; post; pruned; last_step} =
{ pre= normalize_configuration pre
; post= normalize_configuration post
; pruned= normalize_pruned pruned
; last_step }
let normalize_state state = List.map ~f:normalize_simple_state state
let apply_conjuncts_limit state =
let f simple_state = List.length simple_state.pruned <= Config.topl_max_conjuncts in
IList.filter_changed ~f state
let apply_disjuncts_limit state =
if List.length state <= Config.topl_max_disjuncts then state
else
let new_len = (Config.topl_max_disjuncts / 2) + 1 in
let add_score simple_state = (List.length simple_state.pruned, simple_state) in
let compare_score (score1, _simple_state1) (score2, _simple_state2) =
Int.compare score1 score2
in
let strip_score (_score, simple_state) = simple_state in
state |> List.map ~f:add_score |> List.sort ~compare:compare_score |> Fn.flip List.take new_len
|> List.map ~f:strip_score
let apply_limits state = state |> apply_conjuncts_limit |> apply_disjuncts_limit
let small_step loc path_condition event simple_states = let small_step loc path_condition event simple_states =
let simple_states = apply_limits simple_states in
let tmatches = static_match event in let tmatches = static_match event in
let evolve_transition (old : simple_state) (transition, tcontext) : state = let evolve_transition (old : simple_state) (transition, tcontext) : state =
let mk ?(memory = old.post.memory) ?(pruned = []) significant = let mk ?(memory = old.post.memory) ?(pruned = []) significant =
@ -318,13 +354,12 @@ let sub_list sub_elem (sub, xs) =
(sub, List.rev xs) (sub, List.rev xs)
let of_unequal = let of_unequal (or_unequal : 'a List.Or_unequal_lengths.t) =
List.Or_unequal_lengths.( match or_unequal with
function | Ok x ->
| Ok x -> x
x | Unequal_lengths ->
| Unequal_lengths -> L.die InternalError "PulseTopl expected lists to be of equal lengths"
L.die InternalError "PulseTopl expected lists to be of equal lengths")
let sub_configuration (sub, {vertex; memory}) = let sub_configuration (sub, {vertex; memory}) =
@ -361,22 +396,8 @@ let sub_simple_state (sub, {pre; post; pruned; last_step}) =
(sub, {pre; post; pruned; last_step}) (sub, {pre; post; pruned; last_step})
let normalize_memory memory = List.sort ~compare:[%compare: register * value] memory
let normalize_configuration {vertex; memory} = {vertex; memory= normalize_memory memory}
let normalize_pruned pruned = List.sort ~compare:compare_predicate pruned
let normalize_simple_state {pre; post; pruned; last_step} =
{ pre= normalize_configuration pre
; post= normalize_configuration post
; pruned= normalize_pruned pruned
; last_step }
let normalize_state state = List.map ~f:normalize_simple_state state
let large_step ~call_location ~callee_proc_name ~substitution ~condition ~callee_prepost state = let large_step ~call_location ~callee_proc_name ~substitution ~condition ~callee_prepost state =
let state = apply_limits state in
let seq ((p : simple_state), (q : simple_state)) = let seq ((p : simple_state), (q : simple_state)) =
if not (Int.equal p.post.vertex q.pre.vertex) then None if not (Int.equal p.post.vertex q.pre.vertex) then None
else else

Loading…
Cancel
Save