Summary: This diff implements part of the memory management for Objective-C classes in ARC, namely that `dealloc` is called when the objects become unreachable. In reality the semantics of ARC says that this happens when their reference count becomes 0, but we are not modelling this yet in Pulse. However, we could in the future. This fixes false positives memory leaks when the memory is freed in dealloc. `dealloc` is often implicit in Objective-C, it also calls the dealloc of instance variables and superclass. None of this is implemented yet, and will be done in a future diff. This will be added in the frontend probably, similarly to how it's done for C++ destructors. This is an important part of modelling Objective-C semantics in Infer, I looked at whether this should be a preanalysis to be used by all analyses but this needs Pulse. So the idea is that any analysis that needs to understand Objective-C memory model well, should have Pulse as a preanalysis. Reviewed By: jvillard Differential Revision: D21762292 fbshipit-source-id: ced014324master
parent
f638e741ae
commit
aa6fe7963c
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#include <Foundation/NSObject.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@interface BufferContainer1 : NSObject
|
||||
|
||||
@property char* buffer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation BufferContainer1
|
||||
|
||||
- (instancetype)init {
|
||||
_buffer = malloc(sizeof(char));
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
free(_buffer);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface BufferContainer2 : NSObject
|
||||
|
||||
@property char* buffer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation BufferContainer2
|
||||
|
||||
- (instancetype)init {
|
||||
_buffer = malloc(sizeof(char));
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface Araii : NSObject
|
||||
|
||||
@property BufferContainer1* container;
|
||||
|
||||
@end
|
||||
|
||||
@implementation Araii
|
||||
|
||||
- (instancetype)init {
|
||||
_container = [[BufferContainer1 alloc] init];
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/* b goes out of scope, this would cause b->_container to be leaked,
|
||||
however, dealloc is called and _container is freed there, so no leak. */
|
||||
void memory_leak_raii_no_leak_ok() {
|
||||
BufferContainer1* b = [[BufferContainer1 alloc] init];
|
||||
}
|
||||
|
||||
/* b goes out of scope, this causes b->_container to be leaked. Even though
|
||||
dealloc is called, _container is not freed there. */
|
||||
void memory_leak_raii_leak_bad() {
|
||||
BufferContainer2* b = [[BufferContainer2 alloc] init];
|
||||
}
|
||||
|
||||
/* a goes out of scope, this causes a->b->_container to be leaked. This is a FP
|
||||
because dealloc is called, and it should call dealloc of b which would free
|
||||
_container. This behaviour is still to be implemented. */
|
||||
void memory_leak_raii_no_leak_ok_FP() { Araii* a = [[Araii alloc] init]; }
|
Loading…
Reference in new issue