如何修复此 clang 警告:“将具有“0 保留计数的对象返回给调用者,其中需要 1(拥有)保留计数””?

发布于 2024-09-01 18:59:25 字数 1068 浏览 11 评论 0原文

我有一段 Objective-C 代码,如下所示:

- (NSString *)copyData:(NSData *)data
{
    NSString *path = [[[self outputDirectory] stringByAppendingPathComponent:@"archive"] stringByAppendingPathExtension:@"zip"];
    NSLog(@"Copying data to %@", path);
    [data writeToFile:path atomically:NO];
    return path;
}

该代码是从如下所示的初始化程序调用的:

- (id)initWithData:(NSData *)data
{
    if ((self = [super init]) != nil) {
        NSString *path = [self copyData:data];        // Line 41 (referenced in warning, shown below)
        return [self initWithContentsOfFile:path];
    }
    return self;
}

当运行 clang 静态分析器时,我收到以下关于 path 变量的警告:

第 41 行分配并存储到“path”中的对象的潜在泄漏

将 +0 保留计数的对象返回给调用者,其中期望 +1(拥有)保留计数

我很困惑。我的理解是,stringByAppendingPathComponent 应该返回一个自动释放的字符串,因此它应该的净保留计数为0。(显然我不想要保留它。)

我尝试更改 copyData: 以返回以下内容,但它没有消除警告:

return [[path retain] autorelease];

那么这个警告是怎么回事?

I have a piece of Objective-C code that looks like the following:

- (NSString *)copyData:(NSData *)data
{
    NSString *path = [[[self outputDirectory] stringByAppendingPathComponent:@"archive"] stringByAppendingPathExtension:@"zip"];
    NSLog(@"Copying data to %@", path);
    [data writeToFile:path atomically:NO];
    return path;
}

The code is called from an initializer that looks like this:

- (id)initWithData:(NSData *)data
{
    if ((self = [super init]) != nil) {
        NSString *path = [self copyData:data];        // Line 41 (referenced in warning, shown below)
        return [self initWithContentsOfFile:path];
    }
    return self;
}

When running the clang static analyzer, I get the following warnings for the path variable:

Potential leak of an object allocated on line 41 and stored into 'path'

Object with +0 retain counts returned to caller where +1 (owning) retain count is expected

I'm confused. My understanding is that stringByAppendingPathComponent should return an autoreleased string, so it should have a net retain count of 0. (Obviously I don't want to retain it.)

I've tried altering copyData: to return the following, but it didn't get rid of the warning:

return [[path retain] autorelease];

So what's the deal with this warning?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

乖乖哒 2024-09-08 18:59:25

我怀疑它只是注意到一个带有前缀 copy 的方法,并将其标记为应该返回调用者拥有的东西,因为它认为它遵循 Cocoa 命名约定。

当然,就您而言,您指的是文件之类的东西,因此这是一个可以忽略的警告。如果您将方法的名称更改为 saveData: 之类的名称,我敢打赌警告将会消失。

I suspect it's just noticing a method with the prefix copy and flagging that as something that should return something that the caller owns, because it thinks it's following Cocoa naming conventions.

In your case, of course, you are referring to files and whatnot, so it's an ignorable warning. If you change the name of your method, to something like saveData: instead, I bet the warning will go away.

椒妓 2024-09-08 18:59:25

另外,当你确实想用“copy”或其他东西来命名一个方法时,因为无论 Cocoa 内存管理指南如何,copy 是该方法的最佳名称,你可以使用 NS_RETURNS_NOT_RETAINED 然后 Clang 不会给你警告。所以:

// Copies data from data to string; does not follow the copy rule
- (NSString*)copyData:(NSData*)data NS_RETURNS_NOT_RETAINED;

Also, for times where you really do want to name a method with 'copy' or something because regardless of Cocoa memory management guidelines, copy is the best name for the method, you can annotate the method declairation with NS_RETURNS_NOT_RETAINED and then Clang won't give you a warning. So:

// Copies data from data to string; does not follow the copy rule
- (NSString*)copyData:(NSData*)data NS_RETURNS_NOT_RETAINED;
独自←快乐 2024-09-08 18:59:25

由于该方法的名称为 copy,根据 内存管理指南

Since the method has the name copy in it, the analyzer is expecting the returned object to have a +1 retain count, according to the Memory Management Guide.

小…红帽 2024-09-08 18:59:25

不,这是不正确的;除非该方法包含“alloc”、“copy”、“new”或暗示该对象将由调用者拥有的其他关键字之一,否则该方法返回一个自动释放或其他托管对象,因此 stringByAppendingPathComponent 返回一个自动释放的字符串。

最重要的是,您的方法“copyData”包含单词“copy”,这意味着结果应该由调用者拥有(并释放)。但是,您返回的结果已自动发布,因此它会向您显示错误消息。如果您想修复错误,请不要自动释放。那就是:

 return [path retain]

当然,这意味着函数的调用者需要释放它。或者,您可以更改函数的名称,以使其符合内存管理准则。

恕我直言,“copyData”这个名字无论如何都是不直观的。我建议您将函数重命名为“pathToSavedDataWithData”或类似名称。说出它实际上在做什么的东西。

No, that is incorrect; unless the method contains "alloc", "copy", "new", or one of the other keywords that implies the object will be owned by the invoker, the method returns an autoreleased or otherwise managed object, so stringByAppendingPathComponent is returning an autoreleased string.

On top of that, your method "copyData", contains the word "copy", implying that the result should be owned (and released) by the caller. However, the result you returned has been autoreleased, hence the error message that it is giving you. If you want to fix the error, don't autorelease. That is:

 return [path retain]

Of course that implies that the callers of your function need to release it. Alternatively, you can change the name of your function so that it complies with the memory management guidelines.

The name "copyData", IMHO, is unintuitive anyway. I would suggest you rename your function to "pathToSavedDataWithData" or the like. Something that says what it actually is doing.

浅忆流年 2024-09-08 18:59:25

我将对此进行尝试,并猜测无论您的例程名称是否以“copy ...”开头,您都会收到完全相同的错误消息。我刚刚遇到了类似的情况,并且“复制”不是我所调用的例程名称的一部分。 Clang 给出错误消息只是因为我返回了一个自动释放的对象,这是一种危险的情况。 做这个技巧就解决了这个问题。

  return [path retain]  

最后按照迈克尔的建议

I'm going to take a stab at this and guess that you'd get the same exact error message, whether or not the name of your routine started with "copy ..." or not. I just ended up in a similar scenario and "copy" was not part of the name of the routine I was calling. Clang was giving the error message simply because I was returning an autoreleased object, a dangerous situation. Doing the

  return [path retain]  

trick at the end as recommended by Michael took care of the problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文