From c031891d302fa314e0b11389b8b9467e97a13bff Mon Sep 17 00:00:00 2001 From: Sam Blackshear Date: Thu, 8 Feb 2018 19:50:53 -0800 Subject: [PATCH] [litho] fix divergence bug in unroll_call Reviewed By: jeremydubreil Differential Revision: D6941818 fbshipit-source-id: cc2ca85 --- infer/src/checkers/LithoDomain.ml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/infer/src/checkers/LithoDomain.ml b/infer/src/checkers/LithoDomain.ml index a2766d8a8..4082c63ba 100644 --- a/infer/src/checkers/LithoDomain.ml +++ b/infer/src/checkers/LithoDomain.ml @@ -68,24 +68,23 @@ let substitute ~(f_sub: LocalAccessPath.t -> LocalAccessPath.t option) astate = maximal chain. For example, if the domain encodes the chains foo().bar().goo() and foo().baz(), [f] will be called once on foo().bar().goo() and once on foo().baz() *) let iter_call_chains_with_suffix ~f call_suffix astate = - let max_depth = cardinal astate in - let rec unroll_call_ ({receiver; procname}: MethodCall.t) (acc, depth) = - let acc' = procname :: acc in - let depth' = depth + 1 in - let is_cycle access_path = + let rec unroll_call_ ({receiver; procname}: MethodCall.t) (acc, visited) = + let is_cycle (call: MethodCall.t) = (* detect direct cycles and cycles due to mutual recursion *) - LocalAccessPath.equal access_path receiver || depth' > max_depth + LocalAccessPath.equal call.receiver receiver || Typ.Procname.Set.mem call.procname visited in + let acc' = procname :: acc in + let visited' = Typ.Procname.Set.add procname visited in try let calls' = find receiver astate in CallSet.iter (fun call -> - if not (is_cycle call.receiver) then unroll_call_ call (acc', depth') + if not (is_cycle call) then unroll_call_ call (acc', visited') else f receiver.access_path acc' ) calls' with Not_found -> f receiver.access_path acc' in - unroll_call_ call_suffix ([], 0) + unroll_call_ call_suffix ([], Typ.Procname.Set.empty) let iter_call_chains ~f astate =