[arcmt] When a NSData's 'bytes' family of methods are used on a local var,

add __attribute__((objc_precise_lifetime)) to make sure that the object
(and its data) will not get released before the var goes out-of-scope.

rdar://9206226

llvm-svn: 135382
This commit is contained in:
Argyrios Kyrtzidis 2011-07-18 07:44:50 +00:00
parent 73a0d32df5
commit 91c62bfc03
3 changed files with 98 additions and 0 deletions

View File

@ -13,6 +13,8 @@
//
// - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
// with __unsafe_unretained objects.
// - When a NSData's 'bytes' family of methods are used on a local var,
// add __attribute__((objc_precise_lifetime)) to make it safer.
//
//===----------------------------------------------------------------------===//
@ -28,9 +30,13 @@ namespace {
class APIChecker : public RecursiveASTVisitor<APIChecker> {
MigrationPass &Pass;
Selector getReturnValueSel, setReturnValueSel;
Selector getArgumentSel, setArgumentSel;
Selector bytesSel, getBytesSel, getBytesLengthSel, getBytesRangeSel;
llvm::DenseSet<VarDecl *> ChangedNSDataVars;
public:
APIChecker(MigrationPass &pass) : Pass(pass) {
SelectorTable &sels = Pass.Ctx.Selectors;
@ -44,6 +50,14 @@ public:
getArgumentSel = sels.getSelector(2, selIds);
selIds[0] = &ids.get("setArgument");
setArgumentSel = sels.getSelector(2, selIds);
bytesSel = sels.getNullarySelector(&ids.get("bytes"));
getBytesSel = sels.getUnarySelector(&ids.get("getBytes"));
selIds[0] = &ids.get("getBytes");
selIds[1] = &ids.get("length");
getBytesLengthSel = sels.getSelector(2, selIds);
selIds[1] = &ids.get("range");
getBytesRangeSel = sels.getSelector(2, selIds);
}
bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
@ -78,6 +92,26 @@ public:
return true;
}
if (E->isInstanceMessage() &&
E->getReceiverInterface() &&
E->getReceiverInterface()->getName() == "NSData" &&
E->getInstanceReceiver() &&
(E->getSelector() == bytesSel ||
E->getSelector() == getBytesSel ||
E->getSelector() == getBytesLengthSel ||
E->getSelector() == getBytesRangeSel)) {
Expr *rec = E->getInstanceReceiver();
rec = rec->IgnoreParenCasts();
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(rec))
if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
if (VD->hasLocalStorage() && !ChangedNSDataVars.count(VD)) {
Transaction Trans(Pass.TA);
Pass.TA.insertAfterToken(VD->getLocation(),
" __attribute__((objc_precise_lifetime))");
ChangedNSDataVars.insert(VD);
}
}
return true;
}
};

32
clang/test/ARCMT/nsdata.m Normal file
View File

@ -0,0 +1,32 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
#include "Common.h"
@interface NSData : NSObject
- (const void *)bytes;
@end
typedef struct _NSRange {
NSUInteger location;
NSUInteger length;
} NSRange;
@interface NSData (NSExtendedData)
- (void)getBytes:(void *)buffer length:(NSUInteger)length;
- (void)getBytes:(void *)buffer range:(NSRange)range;
@end
@interface NSData (NSDeprecated)
- (void)getBytes:(void *)buffer;
@end
void test(NSData* parmdata) {
NSData *data, *data2 = parmdata;
void *p = [data bytes];
p = [data bytes];
[data2 getBytes:&p length:sizeof(p)];
p = [parmdata bytes];
}

View File

@ -0,0 +1,32 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -x objective-c %s > %t
// RUN: diff %t %s.result
#include "Common.h"
@interface NSData : NSObject
- (const void *)bytes;
@end
typedef struct _NSRange {
NSUInteger location;
NSUInteger length;
} NSRange;
@interface NSData (NSExtendedData)
- (void)getBytes:(void *)buffer length:(NSUInteger)length;
- (void)getBytes:(void *)buffer range:(NSRange)range;
@end
@interface NSData (NSDeprecated)
- (void)getBytes:(void *)buffer;
@end
void test(NSData* parmdata __attribute__((objc_precise_lifetime))) {
NSData *data __attribute__((objc_precise_lifetime)), *data2 __attribute__((objc_precise_lifetime)) = parmdata;
void *p = [data bytes];
p = [data bytes];
[data2 getBytes:&p length:sizeof(p)];
p = [parmdata bytes];
}