(* * Copyright (c) 2018-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 L = Logging type cause = | CppDelete of AccessExpression.t | CppDestructor of Typ.Procname.t * AccessExpression.t | CFree of AccessExpression.t | StdVectorPushBack of AccessExpression.t [@@deriving compare] type t = {cause: cause; location: Location.t} [@@deriving compare] let issue_type_of_cause = function | CppDelete _ -> IssueType.use_after_delete | CppDestructor _ -> IssueType.use_after_lifetime | CFree _ -> IssueType.use_after_free | StdVectorPushBack _ -> IssueType.use_after_lifetime let pp f ({cause; location}[@warning "+9"]) = match cause with | CppDelete access_expr -> F.fprintf f "invalidated by call to `delete %a` at %a" AccessExpression.pp access_expr Location.pp location | CppDestructor (proc_name, access_expr) -> F.fprintf f "invalidated by destructor call `%a(%a)` at %a" Typ.Procname.pp proc_name AccessExpression.pp access_expr Location.pp location | CFree access_expr -> F.fprintf f "invalidated by call to `free(%a)` at %a" AccessExpression.pp access_expr Location.pp location | StdVectorPushBack access_expr -> F.fprintf f "potentially invalidated by call to `std::vector::push_back(%a, ..)` at %a" AccessExpression.pp access_expr Location.pp location module Domain : AbstractDomain.S with type astate = t = struct type astate = t let pp = pp let join i1 i2 = if [%compare.equal: t] i1 i2 then i1 else (* take the max, but it should be unusual for the same location to be invalidated in two different ways *) let kept, forgotten = if compare i1 i2 >= 0 then (i1, i2) else (i2, i1) in L.debug Analysis Quiet "forgetting about invalidation %a for address already invalidated by %a@\n" pp forgotten pp kept ; kept let ( <= ) ~lhs ~rhs = compare lhs rhs <= 0 let widen ~prev ~next ~num_iters:_ = join prev next end include Domain