Adding memory leak bucket for cpp

Reviewed By: @cristianoc

Differential Revision: D2540503

fb-gh-sync-id: 4324009
master
Dulma Rodriguez 9 years ago committed by facebook-github-bot-7
parent 3095b68127
commit 6278b779df

@ -149,12 +149,12 @@ infer_group.add_argument('--absolute-paths',
default=False,
help='Report errors with absolute paths')
infer_group.add_argument('--objc_ml_buckets',
dest='objc_ml_buckets',
infer_group.add_argument('--ml_buckets',
dest='ml_buckets',
help='memory leak buckets to be checked, '
'separated by commas. The possible '
'buckets are cf (Core Foundation), '
'arc, narc (No arc)')
'arc, narc (No arc), cpp')
infer_group.add_argument('-nt', '--notest', action='store_true',
dest='notest',
@ -503,8 +503,8 @@ class Infer:
if self.args.infer_cache:
infer_options += ['-infer_cache', self.args.infer_cache]
if self.args.objc_ml_buckets:
infer_options += ['-objc_ml_buckets', self.args.objc_ml_buckets]
if self.args.ml_buckets:
infer_options += ['-ml_buckets', self.args.ml_buckets]
if self.args.notest:
infer_options += ['-notest']

@ -1129,7 +1129,7 @@ let should_raise_objc_leak prop hpred =
match hpred with
| Sil.Hpointsto(e, Sil.Estruct((fn, Sil.Eexp( (Sil.Const (Sil.Cint i)), _)):: _, _), Sil.Sizeof (typ, _))
when Ident.fieldname_is_hidden fn && Sil.Int.gt i Sil.Int.zero (* counter > 0 *) ->
Mleak_buckets.should_raise_leak typ
Mleak_buckets.should_raise_objc_leak typ
| _ -> None
let print_retain_cycle _prop =
@ -1293,9 +1293,11 @@ let check_junk ?original_prop pname tenv prop =
let resource = match Errdesc.hpred_is_open_resource prop hpred with
| Some res -> res
| None -> Sil.Rmemory Sil.Mmalloc in
let objc_ml_bucket_opt =
let ml_bucket_opt =
match resource with
| Sil.Rmemory Sil.Mobjc -> should_raise_objc_leak prop hpred
| Sil.Rmemory Sil.Mnew when !Config.curr_language = Config.C_CPP ->
Mleak_buckets.should_raise_cpp_leak ()
| _ -> None in
let exn_retain_cycle cycle =
print_retain_cycle original_prop;
@ -1306,7 +1308,7 @@ let check_junk ?original_prop pname tenv prop =
try assert false with Assert_failure x -> x) in
let exn_leak = Exceptions.Leak
(fp_part, prop, hpred,
Errdesc.explain_leak tenv hpred prop alloc_attribute objc_ml_bucket_opt,
Errdesc.explain_leak tenv hpred prop alloc_attribute ml_bucket_opt,
!Absarray.array_abstraction_performed,
resource,
try assert false with Assert_failure x -> x) in
@ -1320,8 +1322,9 @@ let check_junk ?original_prop pname tenv prop =
if cycle_has_weak_or_unretained_or_assign_field cycle then
true, exn_retain_cycle cycle
else false, exn_retain_cycle cycle
| Some _, Sil.Rmemory Sil.Mobjc ->
objc_ml_bucket_opt = None, exn_leak
| Some _, Sil.Rmemory Sil.Mobjc
| Some _, Sil.Rmemory Sil.Mnew when !Config.curr_language = Config.C_CPP ->
ml_bucket_opt = None, exn_leak
| Some _, Sil.Rmemory _ -> !Config.curr_language = Config.Java, exn_leak
| Some _, Sil.Rignore -> true, exn_leak
| Some _, Sil.Rfile -> false, exn_leak

@ -87,8 +87,8 @@ let excluded_files : string list ref = ref []
(** Absolute path to the project source, used for relative paths in the exclude list *)
let source_path = ref ""
(** List of obj memory leak buckets to be checked in objc *)
let objc_ml_buckets_arg = ref "cf"
(** List of obj memory leak buckets to be checked in Objective-C/C++ *)
let ml_buckets_arg = ref "cf"
(** Whether specs can be cleaned up before starting analysis *)
let allow_specs_cleanup = ref false
@ -148,8 +148,8 @@ let arg_desc =
"-version", Arg.Unit print_version, None, "print version information and exit";
"-version_json", Arg.Unit print_version_json, None, "print version json formatted";
"-objcm", Arg.Set Config.objc_memory_model_on, None, "Use ObjC memory model";
"-objc_ml_buckets", Arg.Set_string objc_ml_buckets_arg, Some "objc_ml_buckets",
"memory leak buckets to be checked, separated by commas. The possible buckets are cf (Core Foundation), arc, narc (No arc)";
"-ml_buckets", Arg.Set_string ml_buckets_arg, Some "ml_buckets",
"memory leak buckets to be checked, separated by commas. The possible buckets are cf (Core Foundation), arc, narc (No arc), cpp";
] in
Arg2.create_options_desc false "Analysis Options" desc in
let reserved_arg =
@ -891,7 +891,7 @@ let () =
else !err_file_cmdline in
let analyzer_out_of = open_output_file Logging.set_out_formatter analyzer_out_file in
let analyzer_err_of = open_output_file Logging.set_err_formatter analyzer_err_file in
if (!Config.curr_language = Config.C_CPP) then Mleak_buckets.init_buckets !objc_ml_buckets_arg;
if (!Config.curr_language = Config.C_CPP) then Mleak_buckets.init_buckets !ml_buckets_arg;
process_cluster_cmdline_exit ();

@ -7,7 +7,8 @@
* 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.
*)
(** This module handles buckets of memory leaks in Objective-C *)
(** This module handles buckets of memory leaks in Objective-C/C++ *)
open Utils
@ -19,14 +20,16 @@ type mleak_bucket =
| MLeak_cf
| MLeak_arc
| MLeak_no_arc
| MLeak_cpp
let objc_ml_buckets = ref []
let ml_buckets = ref []
let bucket_from_string bucket_s =
match bucket_s with
| "cf" -> MLeak_cf
| "arc" -> MLeak_arc
| "narc" -> MLeak_no_arc
| "cpp" -> MLeak_cpp
| _ -> assert false
let bucket_to_string bucket =
@ -34,12 +37,14 @@ let bucket_to_string bucket =
| MLeak_cf -> "Core Foundation"
| MLeak_arc -> "Arc"
| MLeak_no_arc -> "No arc"
| MLeak_cpp -> "Cpp"
let bucket_to_message bucket =
match bucket with
| MLeak_cf -> "[CF]"
| MLeak_arc -> "[ARC]"
| MLeak_no_arc -> "[NO ARC]"
| MLeak_cpp -> "[CPP]"
let mleak_bucket_compare b1 b2 =
match b1, b2 with
@ -50,18 +55,21 @@ let mleak_bucket_compare b1 b2 =
| MLeak_arc, _ -> -1
| _, MLeak_arc -> 1
| MLeak_no_arc, MLeak_no_arc -> 0
| MLeak_no_arc, _ -> -1
| _, MLeak_no_arc -> 1
| MLeak_cpp, MLeak_cpp -> 0
let mleak_bucket_eq b1 b2 =
mleak_bucket_compare b1 b2 = 0
let init_buckets objc_ml_buckets_arg =
let init_buckets ml_buckets_arg =
let buckets =
Str.split (Str.regexp bucket_delimiter) objc_ml_buckets_arg in
Str.split (Str.regexp bucket_delimiter) ml_buckets_arg in
let buckets =
match buckets with
| ["all"] -> []
| _ -> list_map bucket_from_string buckets in
objc_ml_buckets := buckets
ml_buckets := buckets
let contains_cf ml_buckets =
list_mem mleak_bucket_eq MLeak_cf ml_buckets
@ -72,28 +80,37 @@ let contains_arc ml_buckets =
let contains_narc ml_buckets =
list_mem mleak_bucket_eq MLeak_no_arc ml_buckets
let contains_cpp ml_buckets =
list_mem mleak_bucket_eq MLeak_cpp ml_buckets
let should_raise_leak_cf typ =
if contains_cf !objc_ml_buckets then
if contains_cf !ml_buckets then
Objc_models.is_core_lib_type typ
else false
let should_raise_leak_arc () =
if contains_arc !objc_ml_buckets then
if contains_arc !ml_buckets then
!Config.arc_mode
else false
let should_raise_leak_no_arc () =
if contains_narc !objc_ml_buckets then
if contains_narc !ml_buckets then
not (!Config.arc_mode)
else false
(* Returns whether a memory leak should be raised. If objc_ml_buckets is not there, *)
(* then raise all memory leaks. *)
(* Returns whether a memory leak should be raised for a C++ object.*)
(* If ml_buckets contains cpp, then check leaks from C++ objects. *)
let should_raise_cpp_leak () =
if contains_cpp !ml_buckets then
Some (bucket_to_message MLeak_cpp)
else None
(* Returns whether a memory leak should be raised. *)
(* If cf is passed, then check leaks from Core Foundation. *)
(* If arc is passed, check leaks from code that compiles with arc*)
(* If no arc is passed check the leaks from code that compiles without arc *)
let should_raise_leak typ =
if list_length !objc_ml_buckets = 0 then Some ""
let should_raise_objc_leak typ =
if list_length !ml_buckets = 0 then Some ""
else
if should_raise_leak_cf typ then Some (bucket_to_message MLeak_cf)
else if should_raise_leak_arc () then Some (bucket_to_message MLeak_arc)

@ -13,10 +13,12 @@ val objc_arc_flag : string
val init_buckets : string -> unit
(* Returns whether a memory leak should be raised. If objc_ml_buckets is not there, *)
(* then raise all memory leaks. *)
(* Returns whether a memory leak should be raised. *)
(* If cf is passed, then check leaks from Core Foundation. *)
(* If arc is passed, check leaks from code that compiles with arc*)
(* If no arc is passed check the leaks from code that compiles without arc *)
val should_raise_leak : Sil.typ -> string option
val should_raise_objc_leak : Sil.typ -> string option
(* Returns whether a memory leak should be raised for a C++ object.*)
(* If ml_buckets contains cpp, then check leaks from C++ objects. *)
val should_raise_cpp_leak : unit -> string option

@ -0,0 +1,20 @@
/*
* Copyright (c) 2015 - 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.
*/
class Rectangle {
int width, height;
public:
Rectangle(int x, int y) : width(x), height(y) {}
int area(void) { return width * height; }
};
int main() {
Rectangle *bar = new Rectangle (5, 6);
return 0;
}

@ -0,0 +1,62 @@
/*
* Copyright (c) 2015 - 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.
*/
package endtoend.cpp;
import static org.hamcrest.MatcherAssert.assertThat;
import static utils.matchers.ResultContainsExactly.containsExactly;
import com.google.common.collect.ImmutableList;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import java.io.IOException;
import utils.DebuggableTemporaryFolder;
import utils.InferException;
import utils.InferResults;
import utils.InferRunner;
public class MemoryLeakCppBucketTest {
public static final String FILE =
"infer/tests/codetoanalyze/cpp/errors/memory_leaks/object_leak.cpp";
private static ImmutableList<String> inferCmd;
public static final String MEMORY_LEAK = "MEMORY_LEAK";
@ClassRule
public static DebuggableTemporaryFolder folder =
new DebuggableTemporaryFolder();
@BeforeClass
public static void runInfer() throws InterruptedException, IOException {
inferCmd = InferRunner.createCPPInferCommandWithMLBuckets(folder, FILE, "cpp");
}
@Test
public void whenInferRunsOnObject_leakThenMLIsFound()
throws InterruptedException, IOException, InferException {
InferResults inferResults = InferRunner.runInferCPP(inferCmd);
String[] methods = { "main" };
assertThat(
"Results should contain " + MEMORY_LEAK,
inferResults,
containsExactly(
MEMORY_LEAK,
FILE,
methods
)
);
}
}

@ -0,0 +1,62 @@
/*
* Copyright (c) 2015 - 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.
*/
package endtoend.cpp;
import static org.hamcrest.MatcherAssert.assertThat;
import static utils.matchers.ResultContainsExactly.containsExactly;
import com.google.common.collect.ImmutableList;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import java.io.IOException;
import utils.DebuggableTemporaryFolder;
import utils.InferException;
import utils.InferResults;
import utils.InferRunner;
public class MemoryLeakTest {
public static final String FILE =
"infer/tests/codetoanalyze/cpp/errors/memory_leaks/object_leak.cpp";
private static ImmutableList<String> inferCmd;
public static final String MEMORY_LEAK = "MEMORY_LEAK";
@ClassRule
public static DebuggableTemporaryFolder folder =
new DebuggableTemporaryFolder();
@BeforeClass
public static void runInfer() throws InterruptedException, IOException {
inferCmd = InferRunner.createCPPInferCommand(folder, FILE);
}
@Test
public void whenInferRunsOnObject_leakThenMLIsNotFound()
throws InterruptedException, IOException, InferException {
InferResults inferResults = InferRunner.runInferCPP(inferCmd);
String[] methods = { }; // no memory leak
assertThat(
"Results should contain " + MEMORY_LEAK,
inferResults,
containsExactly(
MEMORY_LEAK,
FILE,
methods
)
);
}
}

@ -253,7 +253,7 @@ public class InferRunner {
ImmutableList.Builder<String> ml_bucketsOption =
new ImmutableList.Builder<>();
ml_bucketsOption
.add("--objc_ml_buckets")
.add("--ml_buckets")
.add(ml_buckets == null ? "all" : ml_buckets);
ImmutableList<String> inferCmd = new ImmutableList.Builder<String>()
.add("infer")
@ -360,6 +360,20 @@ public class InferRunner {
false);
}
public static ImmutableList<String> createCPPInferCommandWithMLBuckets(
TemporaryFolder folder,
String sourceFile,
String ml_bucket) throws IOException, InterruptedException {
return createClangInferCommand(
folder,
sourceFile,
Language.CPP,
true,
null,
ml_bucket,
false);
}
public static ImmutableList<String> createObjCInferCommand(
TemporaryFolder folder,
String sourceFile) throws IOException, InterruptedException {

Loading…
Cancel
Save