diff --git a/infer/src/backend/interproc.ml b/infer/src/backend/interproc.ml index 1fd37493f..5984051ff 100644 --- a/infer/src/backend/interproc.ml +++ b/infer/src/backend/interproc.ml @@ -772,7 +772,11 @@ let collect_postconditions wl tenv pdesc : Paths.PathSet.t * Specs.Visitedset.t let pathset = match pname with | Procname.ObjC_Cpp _ -> if (Procname.is_constructor pname) then - Paths.PathSet.map (Prop.remove_resource_attribute Sil.Racquire Sil.Rfile) pathset + Paths.PathSet.map (fun prop -> + let prop = Prop.remove_resource_attribute Sil.Racquire Sil.Rfile prop in + let prop = Prop.remove_resource_attribute Sil.Racquire (Sil.Rmemory Sil.Mmalloc) prop in + Prop.remove_resource_attribute Sil.Racquire (Sil.Rmemory Sil.Mobjc) prop + ) pathset else pathset | _ -> pathset in diff --git a/infer/tests/codetoanalyze/cpp/errors/memory_leaks/raii_malloc.cpp b/infer/tests/codetoanalyze/cpp/errors/memory_leaks/raii_malloc.cpp new file mode 100644 index 000000000..cac212f77 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/errors/memory_leaks/raii_malloc.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016 - 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. + */ + +#include + +struct MyResourceManager { + void* p; + MyResourceManager(size_t n) : p(malloc(sizeof(int) * n)) {} + ~MyResourceManager() { free(p); } +}; + +void no_memory_leak() { MyResourceManager resource(1); } + +void memory_leak() { void* p = malloc(sizeof(int)); } diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakRaii.m b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakRaii.m new file mode 100644 index 000000000..9cde8a7aa --- /dev/null +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/MemoryLeakRaii.m @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016 - 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. + */ + +#include +#include + +@interface A : NSObject + +@property char* buffer; + +@end + +@implementation A + +- (instancetype)initWithBuffer { + _buffer = malloc(sizeof(char)); + return self; +} + +- (void)dealloc { + free(_buffer); +} + +@end + +int main() { + [[A alloc] initWithBuffer]; + return 0; +} diff --git a/infer/tests/endtoend/cpp/infer/MemoryLeakRaiiTest.java b/infer/tests/endtoend/cpp/infer/MemoryLeakRaiiTest.java new file mode 100644 index 000000000..9bbf2da6f --- /dev/null +++ b/infer/tests/endtoend/cpp/infer/MemoryLeakRaiiTest.java @@ -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.infer; + +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 MemoryLeakRaiiTest { + + public static final String FILE = + "infer/tests/codetoanalyze/cpp/errors/memory_leaks/raii_malloc.cpp"; + + private static ImmutableList 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 = { "memory_leak" }; + assertThat( + "Results should contain " + MEMORY_LEAK, + inferResults, + containsExactly( + MEMORY_LEAK, + FILE, + methods + ) + ); + } + +} diff --git a/infer/tests/endtoend/objc/infer/MemoryLeakRaiiTest.java b/infer/tests/endtoend/objc/infer/MemoryLeakRaiiTest.java new file mode 100644 index 000000000..36187c7d0 --- /dev/null +++ b/infer/tests/endtoend/objc/infer/MemoryLeakRaiiTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2013 - 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.objc.infer; + +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 MemoryLeakRaiiTest { + + public static final String memory_leak_file = + "infer/tests/codetoanalyze/objc/errors/" + + "memory_leaks_benchmark/MemoryLeakRaii.m"; + + private static ImmutableList 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.createiOSInferCommandWithMLBuckets( + folder, + memory_leak_file, + "cf", + false); + } + + @Test + public void matchErrors() + throws InterruptedException, IOException, InferException { + InferResults inferResults = InferRunner.runInferObjC(inferCmd); + String[] procedures = {}; + assertThat( + "Results should contain the expected memory leak", + inferResults, + containsExactly( + MEMORY_LEAK, + memory_leak_file, + procedures + ) + ); + } + +}