[inferbo] Evaluate cpp vector parameter symbolically

Summary:
This diff evaluates a cpp vector given as a parameter symbolically. Especially, it addresses it as an array, so the cost checker can use its symbolic length correctly.

**About handling `cpp.vector_elem` field:**

The field is a virtual field of vector object that points to the array of vector elements. It was introduced in Inferbo to model semantics of vector operations.
Since many semantics of Inferbo depends on type information, it had collected type information of vector elements, whenever `cpp.vector_elem` field was introduced, as a *side-effect*. A problem is that it has *side-effect*, which means it may introduce non-deterministic analysis results depending on the type information of the virtual field.

This diff changes it not to collect the type information on `cpp.vector_elem` as a side-effect. Instead, it tries to write the information to the abstract states (abstract location) when possible.

Reviewed By: ezgicicek

Differential Revision: D27674935

fbshipit-source-id: f3d52cae7
master
Sungkeun Cho 4 years ago committed by Facebook GitHub Bot
parent 2bdc4e5573
commit 341169ff0f

@ -568,7 +568,7 @@ module PowLoc = struct
mk_known (LocSet.fold (fun l -> LocSet.add (Loc.get_parent_field l)) ploc LocSet.empty) mk_known (LocSet.fold (fun l -> LocSet.add (Loc.get_parent_field l)) ploc LocSet.empty)
let append_field ploc ~fn = let append_field ?typ ploc ~fn =
match ploc with match ploc with
| Bottom -> | Bottom ->
(* Return the unknown location to avoid unintended unreachable nodes *) (* Return the unknown location to avoid unintended unreachable nodes *)
@ -576,7 +576,7 @@ module PowLoc = struct
| Unknown -> | Unknown ->
Unknown Unknown
| Known ploc -> | Known ploc ->
mk_known (LocSet.fold (fun l -> LocSet.add (Loc.append_field l fn)) ploc LocSet.empty) mk_known (LocSet.fold (fun l -> LocSet.add (Loc.append_field ?typ l fn)) ploc LocSet.empty)
let append_star_field ploc ~fn = let append_star_field ploc ~fn =

@ -111,7 +111,7 @@ module PowLoc : sig
val get_parent_field : t -> t val get_parent_field : t -> t
val append_field : t -> fn:Fieldname.t -> t val append_field : ?typ:Typ.t -> t -> fn:Fieldname.t -> t
val append_star_field : t -> fn:Fieldname.t -> t val append_star_field : t -> fn:Fieldname.t -> t

@ -549,104 +549,110 @@ module Val = struct
let traces = traces_of_loc (Loc.of_path deref_path) in let traces = traces_of_loc (Loc.of_path deref_path) in
of_c_array_alloc allocsite ~stride:None ~offset ~size ~traces of_c_array_alloc allocsite ~stride:None ~offset ~size ~traces
in in
let ptr_to_normal_c_array elt =
let deref_kind = SPath.Deref_CPointer in
let deref_path = SPath.deref ~deref_kind path in
let l = Loc.of_path deref_path in
let traces = traces_of_loc l in
let arrayblk =
let allocsite = Allocsite.make_symbol deref_path in
let stride =
match elt with
| Some {Typ.desc= Tint ikind} ->
Itv.of_int (Typ.width_of_ikind integer_type_widths ikind)
| _ ->
Itv.nat
in
let is_void = Typ.is_pointer_to_void typ in
let offset =
if SPath.is_cpp_vector_elem path then Itv.zero else Itv.of_offset_path ~is_void path
in
let size = Itv.of_length_path ~is_void path in
ArrayBlk.make_c allocsite ~stride ~offset ~size
in
{bot with arrayblk; traces}
in
let is_java = Language.curr_language_is Java in let is_java = Language.curr_language_is Java in
L.d_printfln_escaped "Val.of_path %a : %a%s%s" SPath.pp_partial path (Typ.pp Pp.text) typ L.d_printfln_escaped "Val.of_path %a : %a%s%s" SPath.pp_partial path (Typ.pp Pp.text) typ
(if may_last_field then ", may_last_field" else "") (if may_last_field then ", may_last_field" else "")
(if is_java then ", is_java" else "") ; (if is_java then ", is_java" else "") ;
match typ.Typ.desc with match path with
| Tint (IBool | IChar | ISChar | IUChar | IUShort) -> | BoField.Field {fn; typ} when BufferOverrunField.is_cpp_vector_elem fn ->
let v = itv_val ~non_int:is_java in ptr_to_normal_c_array typ
if is_java then set_itv_updated_by_unknown v else set_itv_updated_by_addition v | _ -> (
| Tfloat _ | Tfun | TVar _ -> match typ.Typ.desc with
itv_val ~non_int:true |> set_itv_updated_by_unknown | Tint (IBool | IChar | ISChar | IUChar | IUShort) ->
| Tint _ | Tvoid -> let v = itv_val ~non_int:is_java in
itv_val ~non_int:false |> set_itv_updated_by_addition if is_java then set_itv_updated_by_unknown v else set_itv_updated_by_addition v
| Tptr ({desc= Tfun}, _) -> | Tfloat _ | Tfun | TVar _ ->
of_func_ptrs (FuncPtr.Set.of_path path) itv_val ~non_int:true |> set_itv_updated_by_unknown
| Tptr ({desc= Tstruct name}, _) | Tint _ | Tvoid ->
when PatternMatch.is_subtype tenv name StdTyp.Name.Objc.ns_enumerator -> itv_val ~non_int:false |> set_itv_updated_by_addition
(* NOTE: It generates a value of NSEnumerator specifically. Especially, it assigns zero to | Tptr ({desc= Tfun}, _) ->
the offset, rather than a symbol, to avoid precision loss by limited handling of symbolic of_func_ptrs (FuncPtr.Set.of_path path)
values in the domain. Although this is an unsound design choice, we expect it should not | Tptr ({desc= Tstruct name}, _)
that harmful for calculating WCET. *) when PatternMatch.is_subtype tenv name StdTyp.Name.Objc.ns_enumerator ->
let allocsite = SPath.deref ~deref_kind:Deref_CPointer path |> Allocsite.make_symbol in (* NOTE: It generates a value of NSEnumerator specifically. Especially, it assigns zero to
let size = Itv.of_length_path ~is_void:false path in the offset, rather than a symbol, to avoid precision loss by limited handling of symbolic
{bot with arrayblk= ArrayBlk.make_c allocsite ~offset:Itv.zero ~size ~stride:Itv.one} values in the domain. Although this is an unsound design choice, we expect it should not
| Tptr (elt, _) -> that harmful for calculating WCET. *)
if is_java || SPath.is_this path then let allocsite = SPath.deref ~deref_kind:Deref_CPointer path |> Allocsite.make_symbol in
let deref_kind = let size = Itv.of_length_path ~is_void:false path in
if is_java then SPath.Deref_JavaPointer else SPath.Deref_COneValuePointer {bot with arrayblk= ArrayBlk.make_c allocsite ~offset:Itv.zero ~size ~stride:Itv.one}
in | Tptr (elt, _) ->
let deref_path = SPath.deref ~deref_kind path in if is_java || SPath.is_this path then
let l = Loc.of_path deref_path in let deref_kind =
let traces = traces_of_loc l in if is_java then SPath.Deref_JavaPointer else SPath.Deref_COneValuePointer
{bot with powloc= PowLoc.singleton l; traces}
else
let deref_kind = SPath.Deref_CPointer in
let deref_path = SPath.deref ~deref_kind path in
let l = Loc.of_path deref_path in
let traces = traces_of_loc l in
let arrayblk =
let allocsite = Allocsite.make_symbol deref_path in
let stride =
match elt.Typ.desc with
| Typ.Tint ikind ->
Itv.of_int (Typ.width_of_ikind integer_type_widths ikind)
| _ ->
Itv.nat
in in
let offset = let deref_path = SPath.deref ~deref_kind path in
if SPath.is_cpp_vector_elem path then Itv.zero let l = Loc.of_path deref_path in
else Itv.of_offset_path ~is_void:(Typ.is_pointer_to_void typ) path let traces = traces_of_loc l in
in {bot with powloc= PowLoc.singleton l; traces}
let size = Itv.of_length_path ~is_void:(Typ.is_pointer_to_void typ) path in else ptr_to_normal_c_array (Some elt)
ArrayBlk.make_c allocsite ~stride ~offset ~size | Tstruct typename -> (
in match BufferOverrunTypModels.dispatch tenv typename with
{bot with arrayblk; traces} | Some (CArray {deref_kind; length}) ->
| Tstruct typename -> ( let deref_path = SPath.deref ~deref_kind path in
match BufferOverrunTypModels.dispatch tenv typename with let size = Itv.of_int_lit length in
| Some (CArray {deref_kind; length}) -> ptr_to_c_array_alloc deref_path size
let deref_path = SPath.deref ~deref_kind path in | Some CppStdVector ->
let size = Itv.of_int_lit length in let l = Loc.of_path (SPath.deref ~deref_kind:Deref_CPointer path) in
ptr_to_c_array_alloc deref_path size let traces = traces_of_loc l in
| Some CppStdVector -> of_loc ~traces l
let l = Loc.of_path (SPath.deref ~deref_kind:Deref_CPointer path) in | Some JavaCollection ->
let traces = traces_of_loc l in let deref_path = SPath.deref ~deref_kind:Deref_ArrayIndex path in
of_loc ~traces l let l = Loc.of_path deref_path in
| Some JavaCollection -> let traces = traces_of_loc l in
let allocsite = Allocsite.make_symbol deref_path in
let length = Itv.of_length_path ~is_void:false path in
of_java_array_alloc allocsite ~length ~traces
| Some JavaInteger ->
itv_val ~non_int:false
| None ->
let l = Loc.of_path path in
let traces = traces_of_loc l in
of_loc ~traces l )
| Tarray {length; stride} ->
let deref_path = SPath.deref ~deref_kind:Deref_ArrayIndex path in let deref_path = SPath.deref ~deref_kind:Deref_ArrayIndex path in
let l = Loc.of_path deref_path in let l = Loc.of_path deref_path in
let traces = traces_of_loc l in let traces = traces_of_loc l in
let allocsite = Allocsite.make_symbol deref_path in let allocsite = Allocsite.make_symbol deref_path in
let length = Itv.of_length_path ~is_void:false path in let size =
of_java_array_alloc allocsite ~length ~traces match length with
| Some JavaInteger -> | None (* IncompleteArrayType, no-size flexible array *) ->
itv_val ~non_int:false Itv.of_length_path ~is_void:false path
| None -> | Some length
let l = Loc.of_path path in when may_last_field && (IntLit.iszero length || IntLit.isone length)
let traces = traces_of_loc l in (* 0/1-sized flexible array *) ->
of_loc ~traces l ) Itv.of_length_path ~is_void:false path
| Tarray {length; stride} -> | Some length ->
let deref_path = SPath.deref ~deref_kind:Deref_ArrayIndex path in Itv.of_big_int (IntLit.to_big_int length)
let l = Loc.of_path deref_path in in
let traces = traces_of_loc l in if is_java then of_java_array_alloc allocsite ~length:size ~traces
let allocsite = Allocsite.make_symbol deref_path in else
let size = let stride = Option.map stride ~f:(fun n -> IntLit.to_int_exn n) in
match length with let offset = Itv.zero in
| None (* IncompleteArrayType, no-size flexible array *) -> of_c_array_alloc allocsite ~stride ~offset ~size ~traces )
Itv.of_length_path ~is_void:false path
| Some length
when may_last_field && (IntLit.iszero length || IntLit.isone length)
(* 0/1-sized flexible array *) ->
Itv.of_length_path ~is_void:false path
| Some length ->
Itv.of_big_int (IntLit.to_big_int length)
in
if is_java then of_java_array_alloc allocsite ~length:size ~traces
else
let stride = Option.map stride ~f:(fun n -> IntLit.to_int_exn n) in
let offset = Itv.zero in
of_c_array_alloc allocsite ~stride ~offset ~size ~traces
let on_demand : default:t -> ?typ:Typ.t -> OndemandEnv.t -> Loc.t -> t = let on_demand : default:t -> ?typ:Typ.t -> OndemandEnv.t -> Loc.t -> t =

@ -13,14 +13,10 @@ let pp ~pp_lhs ~sep f lhs fn = F.fprintf f "%a%s%s" pp_lhs lhs sep (Fieldname.ge
let mk, get_type = let mk, get_type =
let class_name = "__infer__" in let class_name = "__infer__" in
let types = ref Fieldname.Map.empty in let types = ref Fieldname.Map.empty in
let mk ?cpp_classname name typ = let mk name typ =
let fieldname = let fieldname =
match cpp_classname with let class_name, field_name = String.rsplit2_exn ~on:'.' (class_name ^ "." ^ name) in
| None -> Fieldname.make (Typ.Name.Java.from_string class_name) field_name
let class_name, field_name = String.rsplit2_exn ~on:'.' (class_name ^ "." ^ name) in
Fieldname.make (Typ.Name.Java.from_string class_name) field_name
| Some classname ->
Fieldname.make classname name
in in
types := Fieldname.Map.add fieldname typ !types ; types := Fieldname.Map.add fieldname typ !types ;
fieldname fieldname
@ -51,7 +47,7 @@ let c_strlen () =
let cpp_vector_elem_str = "cpp.vector_elem" let cpp_vector_elem_str = "cpp.vector_elem"
let cpp_vector_elem ~vec_typ ~elt_typ = let cpp_vector_elem ~vec_typ =
let classname = let classname =
match vec_typ.Typ.desc with match vec_typ.Typ.desc with
| Typ.Tptr (vec_typ, _) -> ( | Typ.Tptr (vec_typ, _) -> (
@ -63,8 +59,8 @@ let cpp_vector_elem ~vec_typ ~elt_typ =
| _ -> | _ ->
L.(die InternalError) "First parameter of constructor should be a pointer." L.(die InternalError) "First parameter of constructor should be a pointer."
in in
let desc = Typ.Tptr (elt_typ, Typ.Pk_pointer) in (* Note: Avoid calling [mk] that has side-effects introducing non-deterministic results *)
mk ~cpp_classname:classname cpp_vector_elem_str {Typ.desc; quals= Typ.mk_type_quals ()} Fieldname.make classname cpp_vector_elem_str
let is_cpp_vector_elem fn = String.equal (Fieldname.to_simplified_string fn) cpp_vector_elem_str let is_cpp_vector_elem fn = String.equal (Fieldname.to_simplified_string fn) cpp_vector_elem_str

@ -23,7 +23,7 @@ val get_type : Fieldname.t -> Typ.t option
val c_strlen : unit -> Fieldname.t val c_strlen : unit -> Fieldname.t
(** Field for C string's length *) (** Field for C string's length *)
val cpp_vector_elem : vec_typ:Typ.t -> elt_typ:Typ.t -> Fieldname.t val cpp_vector_elem : vec_typ:Typ.t -> Fieldname.t
(** Field for C++ vector's elements *) (** Field for C++ vector's elements *)
val java_collection_internal_array : Fieldname.t val java_collection_internal_array : Fieldname.t

@ -479,29 +479,30 @@ module StdArray = struct
end end
module ArrObjCommon = struct module ArrObjCommon = struct
let deref_of {integer_type_widths} exp ~fn mem = let deref_of {integer_type_widths} exp ~fn ?fn_typ mem =
Dom.Val.get_all_locs (Sem.eval_arr integer_type_widths exp mem) |> PowLoc.append_field ~fn let typ = Option.map fn_typ ~f:Typ.mk_ptr in
Dom.Val.get_all_locs (Sem.eval_arr integer_type_widths exp mem) |> PowLoc.append_field ?typ ~fn
let eval_size model_env exp ~fn mem = let eval_size model_env exp ~fn mem =
Sem.eval_array_locs_length (deref_of model_env exp ~fn mem) mem Sem.eval_array_locs_length (deref_of model_env exp ~fn mem) mem
let size_exec exp ~fn ({integer_type_widths} as model_env) ~ret:(id, _) mem = let size_exec exp ~fn ?fn_typ ({integer_type_widths} as model_env) ~ret:(id, _) mem =
let locs = Sem.eval integer_type_widths exp mem |> Dom.Val.get_all_locs in let locs = Sem.eval integer_type_widths exp mem |> Dom.Val.get_all_locs in
match PowLoc.is_singleton_or_more locs with match PowLoc.is_singleton_or_more locs with
| Singleton (BoField.Prim (Loc.Allocsite (Allocsite.LiteralString s))) -> | Singleton (BoField.Prim (Loc.Allocsite (Allocsite.LiteralString s))) ->
model_by_value (Dom.Val.of_int (String.length s)) id mem model_by_value (Dom.Val.of_int (String.length s)) id mem
| _ -> | _ ->
let arr_locs = deref_of model_env exp ~fn mem in let arr_locs = deref_of model_env exp ~fn ?fn_typ mem in
let mem = Dom.Mem.add_stack (Loc.of_id id) (Sem.eval_array_locs_length arr_locs mem) mem in let mem = Dom.Mem.add_stack (Loc.of_id id) (Sem.eval_array_locs_length arr_locs mem) mem in
load_size_alias id arr_locs mem load_size_alias id arr_locs mem
let at arr_exp ~fn index_exp = let at arr_exp ~fn ?fn_typ index_exp =
let exec ({pname; location} as model_env) ~ret:(id, typ) mem = let exec ({pname; location} as model_env) ~ret:(id, typ) mem =
let array_v = let array_v =
let locs = deref_of model_env arr_exp ~fn mem in let locs = deref_of model_env arr_exp ~fn ?fn_typ mem in
if PowLoc.is_bot locs then Dom.Val.unknown_from typ ~callee_pname:(Some pname) ~location if PowLoc.is_bot locs then Dom.Val.unknown_from typ ~callee_pname:(Some pname) ~location
else Dom.Mem.find_set locs mem else Dom.Mem.find_set locs mem
in in
@ -516,13 +517,14 @@ module ArrObjCommon = struct
{exec; check} {exec; check}
let copy_constructor model_env deref_of_tgt ~fn src_exp mem = let copy_constructor model_env deref_of_tgt ~fn ?fn_typ src_exp mem =
let deref_of_src = deref_of model_env src_exp ~fn mem in let deref_of_src = deref_of model_env src_exp ~fn ?fn_typ mem in
Dom.Mem.update_mem deref_of_tgt (Dom.Mem.find_set deref_of_src mem) mem Dom.Mem.update_mem deref_of_tgt (Dom.Mem.find_set deref_of_src mem) mem
let constructor_from_char_ptr ({integer_type_widths} as model_env) tgt_deref ~fn src mem = let constructor_from_char_ptr ({integer_type_widths} as model_env) tgt_deref ~fn ?char_typ src mem
let elem_locs = PowLoc.append_field tgt_deref ~fn in =
let elem_locs = PowLoc.append_field ?typ:(Option.map char_typ ~f:Typ.mk_ptr) tgt_deref ~fn in
match src with match src with
| Exp.Const (Const.Cstr s) -> | Exp.Const (Const.Cstr s) ->
BoUtils.Exec.decl_string model_env ~do_alloc:true elem_locs s mem BoUtils.Exec.decl_string model_env ~do_alloc:true elem_locs s mem
@ -545,16 +547,17 @@ end
module StdVector = struct module StdVector = struct
let append_field loc ~vec_typ ~elt_typ = let append_field loc ~vec_typ ~elt_typ =
Loc.append_field loc (BufferOverrunField.cpp_vector_elem ~vec_typ ~elt_typ) Loc.append_field ~typ:(Typ.mk_ptr elt_typ) loc (BufferOverrunField.cpp_vector_elem ~vec_typ)
let append_fields locs ~vec_typ ~elt_typ = let append_fields locs ~vec_typ ~elt_typ =
PowLoc.append_field locs ~fn:(BufferOverrunField.cpp_vector_elem ~vec_typ ~elt_typ) PowLoc.append_field ~typ:(Typ.mk_ptr elt_typ) locs
~fn:(BufferOverrunField.cpp_vector_elem ~vec_typ)
let deref_of model_env elt_typ {exp= vec_exp; typ= vec_typ} mem = let deref_of model_env elt_typ {exp= vec_exp; typ= vec_typ} mem =
let fn = BufferOverrunField.cpp_vector_elem ~vec_typ ~elt_typ in let fn = BufferOverrunField.cpp_vector_elem ~vec_typ in
ArrObjCommon.deref_of model_env vec_exp ~fn mem ArrObjCommon.deref_of model_env vec_exp ~fn ~fn_typ:(Typ.mk_ptr elt_typ) mem
(* The (3) constructor in https://en.cppreference.com/w/cpp/container/vector/vector *) (* The (3) constructor in https://en.cppreference.com/w/cpp/container/vector/vector *)
@ -591,16 +594,19 @@ module StdVector = struct
(Dom.Val.get_all_locs v, Dom.Val.get_traces v) (Dom.Val.get_all_locs v, Dom.Val.get_traces v)
in in
let deref_of_vec = append_fields vec_locs ~vec_typ ~elt_typ in let deref_of_vec = append_fields vec_locs ~vec_typ ~elt_typ in
let fn = BufferOverrunField.cpp_vector_elem ~vec_typ ~elt_typ in let fn = BufferOverrunField.cpp_vector_elem ~vec_typ in
mem mem
|> Dom.Mem.update_mem vec_locs (Dom.Val.of_pow_loc ~traces deref_of_vec) |> Dom.Mem.update_mem vec_locs (Dom.Val.of_pow_loc ~traces deref_of_vec)
|> ArrObjCommon.copy_constructor model_env deref_of_vec ~fn src_exp |> ArrObjCommon.copy_constructor model_env deref_of_vec ~fn ~fn_typ:(Typ.mk_ptr elt_typ)
src_exp
in in
{exec; check= no_check} {exec; check= no_check}
let at elt_typ {exp= vec_exp; typ= vec_typ} index_exp = let at elt_typ {exp= vec_exp; typ= vec_typ} index_exp =
ArrObjCommon.at vec_exp ~fn:(BufferOverrunField.cpp_vector_elem ~vec_typ ~elt_typ) index_exp ArrObjCommon.at vec_exp
~fn:(BufferOverrunField.cpp_vector_elem ~vec_typ)
~fn_typ:(Typ.mk_ptr elt_typ) index_exp
let set_size {location} locs new_size mem = let set_size {location} locs new_size mem =
@ -651,7 +657,9 @@ module StdVector = struct
let size elt_typ {exp= vec_exp; typ= vec_typ} = let size elt_typ {exp= vec_exp; typ= vec_typ} =
let exec = let exec =
ArrObjCommon.size_exec vec_exp ~fn:(BufferOverrunField.cpp_vector_elem ~vec_typ ~elt_typ) ArrObjCommon.size_exec vec_exp
~fn:(BufferOverrunField.cpp_vector_elem ~vec_typ)
~fn_typ:(Typ.mk_ptr elt_typ)
in in
{exec; check= no_check} {exec; check= no_check}
@ -728,8 +736,8 @@ module StdBasicString = struct
let mem = let mem =
Dom.Mem.update_mem tgt_locs (Dom.Val.of_pow_loc ~traces:Trace.Set.bottom tgt_deref) mem Dom.Mem.update_mem tgt_locs (Dom.Val.of_pow_loc ~traces:Trace.Set.bottom tgt_deref) mem
in in
let fn = BufferOverrunField.cpp_vector_elem ~vec_typ:tgt_typ ~elt_typ:char_typ in let fn = BufferOverrunField.cpp_vector_elem ~vec_typ:tgt_typ in
ArrObjCommon.constructor_from_char_ptr model_env tgt_deref src ~fn mem ArrObjCommon.constructor_from_char_ptr model_env tgt_deref src ~fn ~char_typ mem
in in
let check ({location; integer_type_widths} as model_env) mem cond_set = let check ({location; integer_type_widths} as model_env) mem cond_set =
Option.value_map len_opt ~default:cond_set ~f:(fun len -> Option.value_map len_opt ~default:cond_set ~f:(fun len ->
@ -1324,7 +1332,7 @@ module JavaString = struct
{exec; check= no_check} {exec; check= no_check}
let length exp = {exec= ArrObjCommon.size_exec exp ~fn; check= no_check} let length exp = {exec= ArrObjCommon.size_exec exp ~fn ?fn_typ:None; check= no_check}
(** Given a string of length n, return itv [-1, n_u-1]. *) (** Given a string of length n, return itv [-1, n_u-1]. *)
let range_itv_mone model_env exp mem = let range_itv_mone model_env exp mem =

@ -7,7 +7,7 @@
#include <vector> #include <vector>
namespace CppIsTricky { namespace CppIsTricky {
void FN_vector_size_Bad() { void vector_size_Bad() {
const auto vec = std::vector<int>{1, 2, 3}; const auto vec = std::vector<int>{1, 2, 3};
const int numExpectedElements = 1; const int numExpectedElements = 1;
const auto delta = numExpectedElements - vec.size(); const auto delta = numExpectedElements - vec.size();

@ -44,6 +44,7 @@ codetoanalyze/cpp/bufferoverrun/conditional_proof_obligation.cpp, call_condition
codetoanalyze/cpp/bufferoverrun/conditional_proof_obligation.cpp, call_conditional_minus_2_Bad, 2, INTEGER_OVERFLOW_L1, no_bucket, ERROR, [Call,<LHS trace>,Parameter `size`,Binary operation: (0 - 1):unsigned32 by call to `conditional_minus` ] codetoanalyze/cpp/bufferoverrun/conditional_proof_obligation.cpp, call_conditional_minus_2_Bad, 2, INTEGER_OVERFLOW_L1, no_bucket, ERROR, [Call,<LHS trace>,Parameter `size`,Binary operation: (0 - 1):unsigned32 by call to `conditional_minus` ]
codetoanalyze/cpp/bufferoverrun/conditional_proof_obligation.cpp, call_throw_exception_Bad, 0, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Call,<Offset trace>,Parameter `i`,<Length trace>,Array declaration,Array access: Offset: -5 Size: 10 by call to `throw_exception` ] codetoanalyze/cpp/bufferoverrun/conditional_proof_obligation.cpp, call_throw_exception_Bad, 0, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Call,<Offset trace>,Parameter `i`,<Length trace>,Array declaration,Array access: Offset: -5 Size: 10 by call to `throw_exception` ]
codetoanalyze/cpp/bufferoverrun/conditional_proof_obligation.cpp, throw_exception, 3, UNREACHABLE_CODE, no_bucket, ERROR, [Here] codetoanalyze/cpp/bufferoverrun/conditional_proof_obligation.cpp, throw_exception, 3, UNREACHABLE_CODE, no_bucket, ERROR, [Here]
codetoanalyze/cpp/bufferoverrun/cpp_is_tricky.cpp, CppIsTricky::vector_size_Bad, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [<LHS trace>,Assignment,Binary operation: (1 - [0, +oo]):unsigned64]
codetoanalyze/cpp/bufferoverrun/external.cpp, extern_bad, 5, BUFFER_OVERRUN_U5, no_bucket, ERROR, [<Length trace>,Unknown value from: lib,Assignment,Array access: Offset: [-oo, +oo] Size: [0, +oo]] codetoanalyze/cpp/bufferoverrun/external.cpp, extern_bad, 5, BUFFER_OVERRUN_U5, no_bucket, ERROR, [<Length trace>,Unknown value from: lib,Assignment,Array access: Offset: [-oo, +oo] Size: [0, +oo]]
codetoanalyze/cpp/bufferoverrun/external.cpp, extern_bad, 10, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Length trace>,Array declaration,Array access: Offset: 30 Size: 10] codetoanalyze/cpp/bufferoverrun/external.cpp, extern_bad, 10, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Length trace>,Array declaration,Array access: Offset: 30 Size: 10]
codetoanalyze/cpp/bufferoverrun/folly_split.cpp, folly_split::do_not_ignore_empty_Bad, 3, BUFFER_OVERRUN_L4, no_bucket, ERROR, [<Length trace>,Set array size,Array access: Offset: 0 Size: [0, +oo]] codetoanalyze/cpp/bufferoverrun/folly_split.cpp, folly_split::do_not_ignore_empty_Bad, 3, BUFFER_OVERRUN_L4, no_bucket, ERROR, [<Length trace>,Set array size,Array access: Offset: 0 Size: [0, +oo]]

@ -1,2 +1,5 @@
../../facebook-clang-plugins/clang/install/include/c++/v1/string, std::operator!=<b7ca98c5140c72c>, 37 + 12 ⋅ __lhs->cpp.vector_elem.length.ub(u) + (__lhs->cpp.vector_elem.length.ub(u) + 1), OnUIThread:false, [{__lhs->cpp.vector_elem.length.ub(u) + 1},Call to std::operator==<std::allocator<char>_>,Loop,{__lhs->cpp.vector_elem.length.ub(u)},Call to std::operator==<std::allocator<char>_>,Loop]
../../facebook-clang-plugins/clang/install/include/c++/v1/string, std::operator==<std::allocator<char>_>, 31 + 12 ⋅ __lhs->cpp.vector_elem.length.ub(u) + (__lhs->cpp.vector_elem.length.ub(u) + 1), OnUIThread:false, [{__lhs->cpp.vector_elem.length.ub(u) + 1},Loop,{__lhs->cpp.vector_elem.length.ub(u)},Loop]
codetoanalyze/cpp/performance/string_test.cpp, call_google_strlen_linear, 2 + str->strlen.ub(u), OnUIThread:false, [{str->strlen.ub(u)},Modeled call to google::StrLen] codetoanalyze/cpp/performance/string_test.cpp, call_google_strlen_linear, 2 + str->strlen.ub(u), OnUIThread:false, [{str->strlen.ub(u)},Modeled call to google::StrLen]
codetoanalyze/cpp/performance/string_test.cpp, call_google_strlen_with_loop_linear, 4 + 3 ⋅ str->strlen.ub(u) + str->strlen.ub(u) + 2 ⋅ (str->strlen.ub(u) + 1), OnUIThread:false, [{str->strlen.ub(u) + 1},Loop,{str->strlen.ub(u)},Modeled call to google::StrLen,{str->strlen.ub(u)},Loop] codetoanalyze/cpp/performance/string_test.cpp, call_google_strlen_with_loop_linear, 4 + 3 ⋅ str->strlen.ub(u) + str->strlen.ub(u) + 2 ⋅ (str->strlen.ub(u) + 1), OnUIThread:false, [{str->strlen.ub(u) + 1},Loop,{str->strlen.ub(u)},Modeled call to google::StrLen,{str->strlen.ub(u)},Loop]
codetoanalyze/cpp/performance/string_test.cpp, string_compare_linear, 45 + 12 ⋅ a->cpp.vector_elem.length.ub(u) + (a->cpp.vector_elem.length.ub(u) + 1), OnUIThread:false, [{a->cpp.vector_elem.length.ub(u) + 1},Call to std::operator!=<b7ca98c5140c72c>,Call to std::operator==<std::allocator<char>_>,Loop,{a->cpp.vector_elem.length.ub(u)},Call to std::operator!=<b7ca98c5140c72c>,Call to std::operator==<std::allocator<char>_>,Loop]

@ -5,6 +5,8 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
#include <string>
namespace google { namespace google {
int StrLen(char*); int StrLen(char*);
} }
@ -16,3 +18,10 @@ void call_google_strlen_with_loop_linear(char* str) {
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
} }
} }
void string_compare_linear(const std::string& a, const std::string& b) {
if (a != b) {
return 0;
}
return 1;
}

Loading…
Cancel
Save