diff --git a/infer/src/IR/Sil.re b/infer/src/IR/Sil.re index 826d5de52..76e6fa463 100644 --- a/infer/src/IR/Sil.re +++ b/infer/src/IR/Sil.re @@ -2248,8 +2248,53 @@ let hpred_sub subst => { /** {2 Functions for replacing occurrences of expressions.} */ -let exp_replace_exp epairs e => - List.find f::(fun (e1, _) => Exp.equal e e1) epairs |> Option.value_map f::snd default::e; +let rec exp_replace_exp epairs e => + /* First we check if there is an exact match */ + switch (List.find f::(fun (e1, _) => Exp.equal e e1) epairs) { + | Some (_, e2) => e2 + | None => + /* If e is a compound expression, we need to check for its subexpressions as well */ + switch e { + | Exp.UnOp op e0 ty => + let e0' = exp_replace_exp epairs e0; + if (phys_equal e0 e0') { + e + } else { + Exp.UnOp op e0' ty + } + | Exp.BinOp op lhs rhs => + let lhs' = exp_replace_exp epairs lhs; + let rhs' = exp_replace_exp epairs rhs; + if (phys_equal lhs lhs' && phys_equal rhs rhs') { + e + } else { + Exp.BinOp op lhs' rhs' + } + | Exp.Cast ty e0 => + let e0' = exp_replace_exp epairs e0; + if (phys_equal e0 e0') { + e + } else { + Exp.Cast ty e0' + } + | Exp.Lfield e0 fname ty => + let e0' = exp_replace_exp epairs e0; + if (phys_equal e0 e0') { + e + } else { + Exp.Lfield e0' fname ty + } + | Exp.Lindex base index => + let base' = exp_replace_exp epairs base; + let index' = exp_replace_exp epairs index; + if (phys_equal base base' && phys_equal index index') { + e + } else { + Exp.Lindex base' index' + } + | _ => e + } + }; let atom_replace_exp epairs atom => atom_expmap (fun e => exp_replace_exp epairs e) atom; diff --git a/infer/tests/codetoanalyze/cpp/errors/Makefile b/infer/tests/codetoanalyze/cpp/errors/Makefile index 86029ce20..1fbd051b5 100644 --- a/infer/tests/codetoanalyze/cpp/errors/Makefile +++ b/infer/tests/codetoanalyze/cpp/errors/Makefile @@ -61,6 +61,7 @@ SOURCES = \ shared/types/struct_pass_by_value.cpp \ shared/types/typeid_expr.cpp \ $(wildcard smart_ptr/*.cpp) \ + $(wildcard stack_escape/*.cpp) \ $(wildcard static_local/*.cpp) \ $(wildcard subtyping/*.cpp) \ $(wildcard vector/*.cpp) \ diff --git a/infer/tests/codetoanalyze/cpp/errors/issues.exp b/infer/tests/codetoanalyze/cpp/errors/issues.exp index 45a3d754d..022c57daa 100644 --- a/infer/tests/codetoanalyze/cpp/errors/issues.exp +++ b/infer/tests/codetoanalyze/cpp/errors/issues.exp @@ -122,6 +122,9 @@ codetoanalyze/cpp/errors/smart_ptr/unique_ptr_deref.cpp, unique_ptr::unique_ptr_ codetoanalyze/cpp/errors/smart_ptr/unique_ptr_deref.cpp, unique_ptr::unique_ptr_move_null_deref, 3, NULL_DEREFERENCE, [start of procedure unique_ptr::unique_ptr_move_null_deref()] codetoanalyze/cpp/errors/smart_ptr/unique_ptr_deref.cpp, unique_ptr::unique_ptr_move_ok_deref, 3, UNINITIALIZED_VALUE, [start of procedure unique_ptr::unique_ptr_move_ok_deref()] codetoanalyze/cpp/errors/smart_ptr/unique_ptr_deref.cpp, unique_ptr::unique_ptr_move_ok_deref, 4, MEMORY_LEAK, [start of procedure unique_ptr::unique_ptr_move_ok_deref(),return from a call to unique_ptr::unique_ptr_move_ok_deref] +codetoanalyze/cpp/errors/stack_escape/basic.cpp, basic_escape_local_bad, 3, STACK_VARIABLE_ADDRESS_ESCAPE, [start of procedure basic_escape_local_bad(),return from a call to basic_escape_local_bad] +codetoanalyze/cpp/errors/stack_escape/basic.cpp, basic_escape_param_bad, 0, STACK_VARIABLE_ADDRESS_ESCAPE, [start of procedure basic_escape_param_bad(),return from a call to basic_escape_param_bad] +codetoanalyze/cpp/errors/stack_escape/basic.cpp, escape_local_struct_member_bad, 3, STACK_VARIABLE_ADDRESS_ESCAPE, [start of procedure escape_local_struct_member_bad(),start of procedure EscapeTest,return from a call to EscapeTest_EscapeTest,return from a call to escape_local_struct_member_bad] codetoanalyze/cpp/errors/static_local/nonstatic_local_bad.cpp, nonstatic_local_bad, 3, STACK_VARIABLE_ADDRESS_ESCAPE, [start of procedure nonstatic_local_bad(),return from a call to nonstatic_local_bad] codetoanalyze/cpp/errors/static_local/nonstatic_local_bad.cpp, nonstatic_local_caller, 2, DANGLING_POINTER_DEREFERENCE, [start of procedure nonstatic_local_caller(),start of procedure nonstatic_local_bad(),return from a call to nonstatic_local_bad] codetoanalyze/cpp/errors/subtyping/cast_with_enforce.cpp, cast_with_enforce::cast_with_npe, 3, NULL_DEREFERENCE, [start of procedure cast_with_enforce::cast_with_npe(),start of procedure Base,return from a call to cast_with_enforce::Base_Base] diff --git a/infer/tests/codetoanalyze/cpp/errors/stack_escape/basic.cpp b/infer/tests/codetoanalyze/cpp/errors/stack_escape/basic.cpp new file mode 100644 index 000000000..d5227c67b --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/errors/stack_escape/basic.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2017 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +int* basic_escape_local_bad() { + int a; + return &a; +} + +int* basic_escape_param_bad(int a) { return &a; } + +struct EscapeTest { + int x; +}; +int* escape_local_struct_member_bad() { + EscapeTest esc; + return &(esc.x); +}