From a46130655ec348d240f194579636ab7c8c32c3ff Mon Sep 17 00:00:00 2001 From: Sungkeun Cho Date: Tue, 26 Mar 2019 18:45:45 -0700 Subject: [PATCH] [inferbo] Address __return_param on function calls Summary: In SIL, sometimes a return value is assigned to `__return_param`. Reviewed By: ezgicicek, mbouaziz Differential Revision: D14538590 fbshipit-source-id: dfbb74dc2 --- infer/src/IR/Ident.ml | 3 +++ infer/src/IR/Ident.mli | 3 +++ infer/src/IR/Pvar.ml | 2 ++ infer/src/IR/Pvar.mli | 3 +++ .../bufferoverrun/bufferOverrunAnalysis.ml | 8 ++++++- .../cpp/bufferoverrun/function_call.cpp | 24 +++++++++++++++++++ .../cpp/bufferoverrun/issues.exp | 1 + 7 files changed, 43 insertions(+), 1 deletion(-) diff --git a/infer/src/IR/Ident.ml b/infer/src/IR/Ident.ml index 48525e36e..f5544ba0f 100644 --- a/infer/src/IR/Ident.ml +++ b/infer/src/IR/Ident.ml @@ -156,6 +156,9 @@ end (** Name used for the return variable *) let name_return = Mangled.from_string "return" +(** Name used for the return param variable *) +let name_return_param = Mangled.from_string "__return_param" + (** Return the standard name for the given kind *) let standard_name kind = if equal_kind kind KNormal || equal_kind kind KNone then Name.Normal diff --git a/infer/src/IR/Ident.mli b/infer/src/IR/Ident.mli index 2871dcfd7..3e6684614 100644 --- a/infer/src/IR/Ident.mli +++ b/infer/src/IR/Ident.mli @@ -67,6 +67,9 @@ val name_spec : name val name_return : Mangled.t (** Name used for the return variable *) +val name_return_param : Mangled.t +(** Name used for the return param variable *) + val string_to_name : string -> name (** Convert a string to a name. *) diff --git a/infer/src/IR/Pvar.ml b/infer/src/IR/Pvar.ml index aa64246c0..f7079dce3 100644 --- a/infer/src/IR/Pvar.ml +++ b/infer/src/IR/Pvar.ml @@ -213,6 +213,8 @@ let mk (name : Mangled.t) (proc_name : Typ.Procname.t) : t = let get_ret_pvar pname = mk Ident.name_return pname +let get_ret_param_pvar pname = mk Ident.name_return_param pname + (** [mk_callee name proc_name] creates a program var for a callee function with the given function name *) let mk_callee (name : Mangled.t) (proc_name : Typ.Procname.t) : t = diff --git a/infer/src/IR/Pvar.mli b/infer/src/IR/Pvar.mli index e8c957327..8e172e978 100644 --- a/infer/src/IR/Pvar.mli +++ b/infer/src/IR/Pvar.mli @@ -39,6 +39,9 @@ val get_name : t -> Mangled.t val get_ret_pvar : Typ.Procname.t -> t (** [get_ret_pvar proc_name] retuns the return pvar associated with the procedure name *) +val get_ret_param_pvar : Typ.Procname.t -> t +(** [get_ret_param_pvar proc_name] retuns the return_param pvar associated with the procedure name *) + val get_simplified_name : t -> string (** Get a simplified version of the name component of a program variable. *) diff --git a/infer/src/bufferoverrun/bufferOverrunAnalysis.ml b/infer/src/bufferoverrun/bufferOverrunAnalysis.ml index 68ea66b77..cac88ad7f 100644 --- a/infer/src/bufferoverrun/bufferOverrunAnalysis.ml +++ b/infer/src/bufferoverrun/bufferOverrunAnalysis.ml @@ -94,7 +94,13 @@ module TransferFunctions = struct Option.value_map ret_alias ~default:mem ~f:(fun l -> Dom.Mem.load_alias ret_id l mem) in let ret_var = Loc.of_var (Var.of_id ret_id) in - let ret_val = Dom.Mem.find (Loc.of_pvar (Pvar.get_ret_pvar callee_pname)) callee_exit_mem in + let ret_val = + let val_of_return_var = + Dom.Mem.find_opt (Loc.of_pvar (Pvar.get_ret_pvar callee_pname)) callee_exit_mem + in + IOption.value_default_f val_of_return_var ~f:(fun () -> + Dom.Val.of_loc (Loc.of_pvar (Pvar.get_ret_param_pvar callee_pname)) ) + in Dom.Mem.add_stack ret_var (Dom.Val.subst ret_val eval_sym_trace location) mem |> instantiate_ret_alias |> copy_reachable_locs_from (PowLoc.join formal_locs (Dom.Val.get_all_locs ret_val)) diff --git a/infer/tests/codetoanalyze/cpp/bufferoverrun/function_call.cpp b/infer/tests/codetoanalyze/cpp/bufferoverrun/function_call.cpp index 58c03354f..7c8646b63 100644 --- a/infer/tests/codetoanalyze/cpp/bufferoverrun/function_call.cpp +++ b/infer/tests/codetoanalyze/cpp/bufferoverrun/function_call.cpp @@ -26,3 +26,27 @@ void call_by_ref_bad() { ref_set_to_zero(i); arr[i - 1] = 123; } + +struct S init_S(int x) { + struct S s = {x}; + return s; +} + +int loop_with_init_S(int length) { + int i = 0; + while (i < length) { + struct S s = init_S(i + 1); + i = s.field; + } + return i; +} + +void call_loop_with_init_S_Good() { + int a[10]; + a[loop_with_init_S(5)] = 0; +} + +void call_loop_with_init_S_Bad() { + int a[10]; + a[loop_with_init_S(10)] = 0; +} diff --git a/infer/tests/codetoanalyze/cpp/bufferoverrun/issues.exp b/infer/tests/codetoanalyze/cpp/bufferoverrun/issues.exp index 63a1eda22..863df4cba 100644 --- a/infer/tests/codetoanalyze/cpp/bufferoverrun/issues.exp +++ b/infer/tests/codetoanalyze/cpp/bufferoverrun/issues.exp @@ -51,6 +51,7 @@ codetoanalyze/cpp/bufferoverrun/folly_split.cpp, folly_split::do_not_ignore_empt codetoanalyze/cpp/bufferoverrun/folly_split.cpp, folly_split::do_not_ignore_empty_Bad, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [Call,Call,Assignment,Through,Call,Parameter `this->infer_size`,Call,,Parameter `this->infer_size`,Binary operation: (4 × [0, +oo]):unsigned64] codetoanalyze/cpp/bufferoverrun/folly_split.cpp, folly_split::do_not_ignore_empty_Good, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [Call,Call,Assignment,Through,Call,Parameter `this->infer_size`,Call,,Parameter `this->infer_size`,Binary operation: (4 × [1, +oo]):unsigned64] codetoanalyze/cpp/bufferoverrun/function_call.cpp, call_by_ref_bad, 4, BUFFER_OVERRUN_L1, no_bucket, ERROR, [,Call,Assignment,,Array declaration,Array access: Offset: -1 Size: 10] +codetoanalyze/cpp/bufferoverrun/function_call.cpp, call_loop_with_init_S_Bad, 2, BUFFER_OVERRUN_L1, no_bucket, ERROR, [,Call,Parameter `length`,Assignment,,Array declaration,Array access: Offset: 10 Size: 10] codetoanalyze/cpp/bufferoverrun/realloc.cpp, realloc_Bad, 4, BUFFER_OVERRUN_L1, no_bucket, ERROR, [,Assignment,,Array declaration,Assignment,Array access: Offset: 5 Size: 5] codetoanalyze/cpp/bufferoverrun/realloc.cpp, realloc_flexible_array_Bad, 4, BUFFER_OVERRUN_L1, no_bucket, ERROR, [,Array declaration,Array access: Offset: 7 Size: 5] codetoanalyze/cpp/bufferoverrun/realloc.cpp, realloc_struct1_Bad, 4, BUFFER_OVERRUN_L1, no_bucket, ERROR, [,Assignment,,Array declaration,Assignment,Array access: Offset: 5 Size: 5]