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
|
// - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
|
||||||
// with __unsafe_unretained objects.
|
// 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> {
|
class APIChecker : public RecursiveASTVisitor<APIChecker> {
|
||||||
MigrationPass &Pass;
|
MigrationPass &Pass;
|
||||||
|
|
||||||
Selector getReturnValueSel, setReturnValueSel;
|
Selector getReturnValueSel, setReturnValueSel;
|
||||||
Selector getArgumentSel, setArgumentSel;
|
Selector getArgumentSel, setArgumentSel;
|
||||||
|
|
||||||
|
Selector bytesSel, getBytesSel, getBytesLengthSel, getBytesRangeSel;
|
||||||
|
|
||||||
|
llvm::DenseSet<VarDecl *> ChangedNSDataVars;
|
||||||
public:
|
public:
|
||||||
APIChecker(MigrationPass &pass) : Pass(pass) {
|
APIChecker(MigrationPass &pass) : Pass(pass) {
|
||||||
SelectorTable &sels = Pass.Ctx.Selectors;
|
SelectorTable &sels = Pass.Ctx.Selectors;
|
||||||
|
@ -44,6 +50,14 @@ public:
|
||||||
getArgumentSel = sels.getSelector(2, selIds);
|
getArgumentSel = sels.getSelector(2, selIds);
|
||||||
selIds[0] = &ids.get("setArgument");
|
selIds[0] = &ids.get("setArgument");
|
||||||
setArgumentSel = sels.getSelector(2, selIds);
|
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) {
|
bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
|
||||||
|
@ -78,6 +92,26 @@ public:
|
||||||
return true;
|
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;
|
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