You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
3.5 KiB

(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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 L = Logging
module SPath = Symb.SymbolPath
module FormalTyps = Caml.Map.Make (Pvar)
type t =
{ tenv: Tenv.t
; typ_of_param_path: SPath.partial -> Typ.t option
; may_last_field: SPath.partial -> bool
; entry_location: Location.t
; integer_type_widths: Typ.IntegerWidths.t
; class_name: Typ.name option }
let mk pdesc =
let formal_typs =
List.fold (Procdesc.get_pvar_formals pdesc) ~init:FormalTyps.empty ~f:(fun acc (formal, typ) ->
FormalTyps.add formal typ acc )
in
fun tenv integer_type_widths ->
let rec typ_of_param_path = function
| SPath.Pvar x ->
FormalTyps.find_opt x formal_typs
| SPath.Deref (_, x) -> (
match typ_of_param_path x with
| None ->
None
| Some typ -> (
match typ.Typ.desc with
| Tptr (typ, _) ->
Some typ
| Tarray {elt} ->
Some elt
| Tvoid ->
Some Typ.void
| Tstruct typename -> (
match BufferOverrunTypModels.dispatch tenv typename with
| Some (CArray {element_typ}) ->
Some element_typ
| Some CppStdVector ->
Some (Typ.mk (Typ.Tptr (Typ.void, Typ.Pk_pointer)))
| Some JavaCollection ->
(* Current Java frontend does give element types of Java collection. *)
None
| Some JavaInteger ->
L.internal_error "Deref of non-array modeled type `%a`" Typ.Name.pp typename ;
None
| None ->
L.(die InternalError) "Deref of unmodeled type `%a`" Typ.Name.pp typename )
| _ ->
L.(die InternalError) "Untyped expression is given." ) )
| SPath.Field {typ= Some _ as some_typ} ->
some_typ
| SPath.Field {fn; prefix= x} -> (
match BufferOverrunField.get_type fn with
| None ->
let lookup = Tenv.lookup tenv in
Option.map (typ_of_param_path x) ~f:(Struct.fld_typ ~lookup ~default:Typ.void fn)
| some_typ ->
some_typ )
| SPath.StarField {last_field} ->
BufferOverrunField.get_type last_field
| SPath.Callsite {ret_typ} ->
Some ret_typ
in
let is_last_field fn (fields : Struct.field list) =
Option.value_map (List.last fields) ~default:false ~f:(fun (last_fn, _, _) ->
Fieldname.equal fn last_fn )
in
let rec may_last_field = function
| SPath.Pvar _ | SPath.Deref _ | SPath.Callsite _ ->
true
| SPath.Field {fn; prefix= x} | SPath.StarField {last_field= fn; prefix= x} ->
may_last_field x
&& Option.value_map ~default:true (typ_of_param_path x) ~f:(fun parent_typ ->
match parent_typ.Typ.desc with
| Tstruct typename ->
let opt_struct = Tenv.lookup tenv typename in
Option.value_map opt_struct ~default:false ~f:(fun str ->
is_last_field fn str.Struct.fields )
| _ ->
true )
in
let entry_location = Procdesc.Node.get_loc (Procdesc.get_start_node pdesc) in
let class_name = Procname.get_class_type_name (Procdesc.get_proc_name pdesc) in
{tenv; typ_of_param_path; may_last_field; entry_location; integer_type_widths; class_name}