(* * 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 type t = | AccessToInvalidAddress of { access: HilExp.AccessExpression.t ; invalidated_by: PulseInvalidation.t PulseTrace.action ; accessed_by: HilExp.AccessExpression.t PulseTrace.action ; trace: PulseTrace.breadcrumbs } | StackVariableAddressEscape of { variable: Var.t ; trace: PulseTrace.breadcrumbs ; location: Location.t } let describe_access = PulseTrace.pp_action (Pp.in_backticks HilExp.AccessExpression.pp) let describe_invalidation = PulseTrace.pp_action PulseInvalidation.describe let get_location = function | AccessToInvalidAddress {accessed_by} -> PulseTrace.outer_location_of_action accessed_by | StackVariableAddressEscape {location} -> location let get_message = function | AccessToInvalidAddress {access; accessed_by; invalidated_by; _} -> (* TODO: [access] might be something irrelevant to the user, shouldn't print it in that case *) let line_of_action action = let {Location.line; _} = PulseTrace.outer_location_of_action action in line in let invalidation_line = line_of_action invalidated_by in let access_line = line_of_action accessed_by in let pp_indirect_access f = let erroneous_access = PulseTrace.immediate_of_action accessed_by in if not (HilExp.AccessExpression.equal erroneous_access access) then F.fprintf f " via %a" describe_access accessed_by in F.asprintf "access to `%a`%t at line %d is to %a on line %d" HilExp.AccessExpression.pp access pp_indirect_access access_line describe_invalidation invalidated_by invalidation_line | StackVariableAddressEscape {variable; _} -> let pp_var f var = if Var.is_cpp_temporary var then F.pp_print_string f "C++ temporary" else F.fprintf f "stack variable `%a`" Var.pp var in F.asprintf "address of %a is returned by the function" pp_var variable let add_errlog_header ~title location errlog = let depth = 0 in let tags = [] in Errlog.make_trace_element depth location title tags :: errlog let get_trace = function | AccessToInvalidAddress {accessed_by; invalidated_by; trace} -> let add_header_if_some ~title location_opt errlog = match location_opt with | None -> errlog | Some location -> add_errlog_header ~title location errlog in let pp_invalid_access f access = F.fprintf f "invalid access to `%a`" HilExp.AccessExpression.pp access in add_errlog_header ~title:"invalidation part of the trace starts here" (PulseTrace.outer_location_of_action invalidated_by) @@ PulseTrace.add_errlog_of_action ~nesting:1 PulseInvalidation.describe invalidated_by @@ add_errlog_header ~title:"use-after-lifetime part of the trace starts here" (PulseTrace.outer_location_of_action accessed_by) @@ PulseTrace.add_errlog_of_action ~nesting:1 pp_invalid_access accessed_by @@ add_header_if_some ~title:"trace of how the access expression was constructed starts here" (PulseTrace.start_location_of_breadcrumbs trace) @@ PulseTrace.add_errlog_of_breadcrumbs ~nesting:1 trace @@ [] | StackVariableAddressEscape {trace; location; _} -> PulseTrace.add_errlog_of_breadcrumbs ~nesting:0 trace @@ let nesting = 0 in [Errlog.make_trace_element nesting location "returned here" []] let get_issue_type = function | AccessToInvalidAddress {invalidated_by} -> PulseTrace.immediate_of_action invalidated_by |> PulseInvalidation.issue_type_of_cause | StackVariableAddressEscape _ -> IssueType.stack_variable_address_escape