diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index d69f50a9a2f4938e26cc3c0f1b80948b45609238..e2baf38e0beb05d68eef54b5ccf26faa80ec3f84 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -885,6 +885,8 @@ public: virtual RuntimeDefinition getRuntimeDefinition() const; + virtual bool argumentsMayEscape() const; + virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, BindingsTy &Bindings) const; diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 82a1aa22579c1fea27b8be3b103c0d65d2dd648a..87d7e89e52ebe0b70af08815faaaf269aaf3dbc4 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1907,7 +1907,8 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( // that the pointers get freed by following the container itself. if (FirstSlot.startswith("addPointer") || FirstSlot.startswith("insertPointer") || - FirstSlot.startswith("replacePointer")) { + FirstSlot.startswith("replacePointer") || + FirstSlot.equals("valueWithPointer")) { return true; } diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index e0392bd147301a6466930789298693eecc010a41..838d273cc0af188785ed53cc87c601e2aecde985 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -886,6 +886,17 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { return RuntimeDefinition(); } +bool ObjCMethodCall::argumentsMayEscape() const { + if (isInSystemHeader() && !isInstanceMessage()) { + Selector Sel = getSelector(); + if (Sel.getNumArgs() == 1 && + Sel.getIdentifierInfoForSlot(0)->isStr("valueWithPointer")) + return true; + } + + return CallEvent::argumentsMayEscape(); +} + void ObjCMethodCall::getInitialStackFrameContents( const StackFrameContext *CalleeCtx, BindingsTy &Bindings) const { diff --git a/test/Analysis/Inputs/system-header-simulator-objc.h b/test/Analysis/Inputs/system-header-simulator-objc.h index 3e1d9555bbde154d8b475c787a07b27d14ee27ea..8a5d3b6403c8913a23c7f1fac78f2aec1dd9a0d5 100644 --- a/test/Analysis/Inputs/system-header-simulator-objc.h +++ b/test/Analysis/Inputs/system-header-simulator-objc.h @@ -66,8 +66,11 @@ typedef struct { NSFastEnumerationState; @protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; @end @class NSString, NSDictionary; -@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value; -@end @interface NSNumber : NSValue - (char)charValue; +@interface NSValue : NSObject <NSCopying, NSCoding> ++ (NSValue *)valueWithPointer:(const void *)p; +- (void)getValue:(void *)value; +@end +@interface NSNumber : NSValue - (char)charValue; - (id)initWithInt:(int)value; @end @class NSString; @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count; diff --git a/test/Analysis/malloc.m b/test/Analysis/malloc.m index ad16db52dff966f08cfdafc0e1de58d4cd1ce2c9..9201c2b75fe6a94023f3246a4c907e972f104b87 100644 --- a/test/Analysis/malloc.m +++ b/test/Analysis/malloc.m @@ -49,4 +49,9 @@ void _ArrayCreate() { void testNSDataTruePositiveLeak() { char *b = (char *)malloc(12); NSData *d = [[NSData alloc] initWithBytes: b length: 12]; // expected-warning {{Potential leak of memory pointed to by 'b'}} +} + +id wrapInNSValue() { + void *buffer = malloc(4); + return [NSValue valueWithPointer:buffer]; // no-warning } \ No newline at end of file