forked from OSchip/llvm-project
[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:
parent
73a0d32df5
commit
91c62bfc03
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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];
|
||||
}
|
|
@ -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];
|
||||
}
|
Loading…
Reference in New Issue