From: Argyrios Kyrtzidis Date: Mon, 18 Jul 2011 07:44:50 +0000 (+0000) Subject: [arcmt] When a NSData's 'bytes' family of methods are used on a local var, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=05fdf9bc3f5089db291484e4ad9880aa432db9f4;p=clang [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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135382 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/ARCMigrate/TransAPIUses.cpp b/lib/ARCMigrate/TransAPIUses.cpp index 58fd3d07d0..296aa07000 100644 --- a/lib/ARCMigrate/TransAPIUses.cpp +++ b/lib/ARCMigrate/TransAPIUses.cpp @@ -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 { MigrationPass &Pass; + Selector getReturnValueSel, setReturnValueSel; Selector getArgumentSel, setArgumentSel; + Selector bytesSel, getBytesSel, getBytesLengthSel, getBytesRangeSel; + + llvm::DenseSet 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(rec)) + if (VarDecl *VD = dyn_cast(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; } }; diff --git a/test/ARCMT/nsdata.m b/test/ARCMT/nsdata.m new file mode 100644 index 0000000000..c4a555d5bd --- /dev/null +++ b/test/ARCMT/nsdata.m @@ -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]; +} diff --git a/test/ARCMT/nsdata.m.result b/test/ARCMT/nsdata.m.result new file mode 100644 index 0000000000..0ca2a713b5 --- /dev/null +++ b/test/ARCMT/nsdata.m.result @@ -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]; +}