Summary: This diff adds a new experimental checker for detecting size of objects in autorelease pool in ObjC. The basic mechanism is almost the same with the previous cost calculation: * Autorelease pool size is increased at explicit `autorelease` call * Autorelease pool size is set as zero by the `autoreleasepool` block. While it only supports the explicit calls as of now, we will extend the checker to handle more cases in the following diffs. Reviewed By: ezgicicek Differential Revision: D23473145 fbshipit-source-id: 416488176master
parent
4dbfb72260
commit
cb4cf115e1
@ -0,0 +1,19 @@
|
|||||||
|
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
#
|
||||||
|
# This source code is licensed under the MIT license found in the
|
||||||
|
# LICENSE file in the root directory of this source tree.
|
||||||
|
|
||||||
|
TESTS_DIR = ../../..
|
||||||
|
|
||||||
|
CLANG_OPTIONS = -c $(OBJC_CLANG_OPTIONS)
|
||||||
|
INFER_OPTIONS = --cost-only --debug-exceptions --project-root $(TESTS_DIR)
|
||||||
|
INFERPRINT_OPTIONS = --issues-tests
|
||||||
|
INFERPRINT_COST_OPTIONS = --cost-tests-only-autoreleasepool --cost-issues-tests
|
||||||
|
|
||||||
|
SOURCES = $(wildcard *.m)
|
||||||
|
|
||||||
|
include $(TESTS_DIR)/clang.make
|
||||||
|
include $(TESTS_DIR)/objc.make
|
||||||
|
include $(TESTS_DIR)/cost.make
|
||||||
|
|
||||||
|
infer-out/report.json: $(MAKEFILE_LIST)
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface Basic : NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation Basic
|
||||||
|
|
||||||
|
- (void)call_autorelease_constant {
|
||||||
|
NSString* x = [[NSString alloc] initWith:"test"];
|
||||||
|
return [x autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)autoreleased_in_loop_linear:(int)n {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
[self call_autorelease_constant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)autoreleased_in_autoreleasepool_zero:(int)n {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
@autoreleasepool {
|
||||||
|
[self call_autorelease_constant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is problematic because autoreleased objects inside the loop
|
||||||
|
will not be released until the loop terminates. However, the checker is not
|
||||||
|
measuring peak memory but size of autoreleasepool increased by the function.
|
||||||
|
Since we wrap the loop inside the autoreleasepool block, we will be setting
|
||||||
|
the size to 0 for the whole function. */
|
||||||
|
- (void)loop_in_autoreleasepool_zero:(int)n {
|
||||||
|
@autoreleasepool {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
[self call_autorelease_constant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)autoreleased_in_loop_nested_zero:(int)n {
|
||||||
|
@autoreleasepool {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
for (int j = 0; j < n; j++) {
|
||||||
|
[self call_autorelease_constant];
|
||||||
|
}
|
||||||
|
@autoreleasepool {
|
||||||
|
[self call_autorelease_constant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)autoreleased_in_loop_sequential_constant:(int)n {
|
||||||
|
@autoreleasepool {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
[self call_autorelease_constant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[self call_autorelease_constant];
|
||||||
|
@autoreleasepool {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
[self call_autorelease_constant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)autoreleased_in_loop_sequential_linear:(int)n {
|
||||||
|
@autoreleasepool {
|
||||||
|
[self call_autorelease_constant];
|
||||||
|
}
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
[self call_autorelease_constant];
|
||||||
|
}
|
||||||
|
@autoreleasepool {
|
||||||
|
[self call_autorelease_constant];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)call_no_autorelease_zero {
|
||||||
|
NSString* x = [[NSString alloc] initWith:"test"];
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)no_autoreleased_in_loop_zero:(int)n {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
[self call_no_autorelease];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,10 @@
|
|||||||
|
codetoanalyze/objc/autoreleasepool/basic.m, Basic.autoreleased_in_autoreleasepool_zero:, 0, OnUIThread:false, []
|
||||||
|
codetoanalyze/objc/autoreleasepool/basic.m, Basic.autoreleased_in_loop_linear:, n, OnUIThread:false, [{n},Loop]
|
||||||
|
codetoanalyze/objc/autoreleasepool/basic.m, Basic.autoreleased_in_loop_nested_zero:, 0, OnUIThread:false, []
|
||||||
|
codetoanalyze/objc/autoreleasepool/basic.m, Basic.autoreleased_in_loop_sequential_constant:, 1, OnUIThread:false, []
|
||||||
|
codetoanalyze/objc/autoreleasepool/basic.m, Basic.autoreleased_in_loop_sequential_linear:, n, OnUIThread:false, [{n},Loop]
|
||||||
|
codetoanalyze/objc/autoreleasepool/basic.m, Basic.call_autorelease_constant, 1, OnUIThread:false, []
|
||||||
|
codetoanalyze/objc/autoreleasepool/basic.m, Basic.call_no_autorelease_zero, 0, OnUIThread:false, []
|
||||||
|
codetoanalyze/objc/autoreleasepool/basic.m, Basic.dealloc, 0, OnUIThread:false, []
|
||||||
|
codetoanalyze/objc/autoreleasepool/basic.m, Basic.loop_in_autoreleasepool_zero:, 0, OnUIThread:false, []
|
||||||
|
codetoanalyze/objc/autoreleasepool/basic.m, Basic.no_autoreleased_in_loop_zero:, 0, OnUIThread:false, []
|
Loading…
Reference in new issue