(* * Copyright (c) 2017-present, Facebook, Inc. * * 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 module FiniteBounds = struct type t = int let ( <= ) ~lhs ~rhs = lhs <= rhs let join a b = max a b let widen ~prev ~next ~num_iters:_ = join prev next let pp fmt astate = F.fprintf fmt "%d" astate end module BoundsWithTop = struct open AbstractDomain.Types include AbstractDomain.TopLifted (FiniteBounds) let widening_threshold = 5 let widen ~prev ~next ~num_iters = match (prev, next) with | Top, _ | _, Top -> Top | NonTop prev, NonTop next when num_iters < widening_threshold -> NonTop (FiniteBounds.join prev next) | NonTop _, NonTop _ (* num_iters >= widening_threshold *) -> Top end module ReturnsResource = AbstractDomain.BooleanOr include AbstractDomain.Pair (BoundsWithTop) (ReturnsResource) open AbstractDomain.Types let initial = (NonTop 0, false) let acquire_resource = function | (Top, _) as astate -> astate | NonTop held, returns_resource -> (NonTop (held + 1), returns_resource) let release_resource = function | (Top, _) as astate -> astate | NonTop held, returns_resource -> (NonTop (held - 1), returns_resource) let has_leak = function | Top, _ -> (* UNSOUND but likely that the analyzer got confused *) false | NonTop x, _ when x > 0 -> true | NonTop _, _ -> false let apply_summary ~summary:(summary_count, summary_returns_resource) (current_count, current_returns_resource) = let new_count = match current_count with | Top -> Top | NonTop current_count -> let return_count = if summary_returns_resource then 1 else 0 in let summary_count = match summary_count with Top -> (* confusion => ignore *) 0 | NonTop count -> count in NonTop (current_count + summary_count + return_count) in (new_count, current_returns_resource) let record_return_resource (count, _) = (count, true) type summary = t