权限被拒绝,由 NSURL 资源泄漏引起?

Permission denied, caused by an NSURL resource leak?

我的 Mac 应用会复制用户拖入的文件。该应用是沙盒化的。我现在有一个错误,我可以在 Xcode 中可靠地重现它,但我无法追踪它的来源。

当我添加一定数量的文件时,应用程序突然无法访问后面的文件。所有源文件都从同一父目录向下一级,并且其间的所有文件夹都具有相同的权限,已通过 ls -l 验证。该应用保留了 Destination Directory 的应用范围书签,在创建 .directoryName 和开始文件复制之前访问该书签。

我收到错误:

Error Domain=NSCocoaErrorDomain Code=513 "“Filename.ext” couldn’t be copied because you don’t have permission to access “.directoryName”." UserInfo=0x6080000eaf80 {NSSourceFilePathErrorKey=/Users/Username/Parent Directory/Subdir/Filename.ext, NSUserStringVariant=( Copy ), NSDestinationFilePath=/Users/Username/Desktop/Destination Directory/.directoryName/Filename.ext, NSFilePath=/Users/Username/Parent Directory/Subdir/Filename.ext, NSUnderlyingError=0x6080004567a0 "The operation couldn’t be completed. Operation not permitted"}

我在调试时做了以下操作:

  1. 尝试在退出并重新启动后自行添加 Subdir/Filename.ext,效果很好
  2. 已验证(使用 lsof 和 Activity 监视器)我没有泄漏文件句柄(我知道这在过去对我造成了类似的问题)
  3. 已使用符号断点验证每次对 -[NSURL startAccessingSecurityScopedResource] 的调用都与对 -[NSURL stopAccessingSecurityScopedResource](及其 CF 等价物)的调用保持平衡
  4. 确定 Filename.ext 和其他失败的文件在没有其他文件的情况下添加成功
  5. 在调试器内部和外部,调试和发布版本会出现相同的行为
  6. 我尝试 运行ning 作为 root,但我的应用程序不会 运行 这样。当在调试器中 运行ning 时,我得到一个 EXC_BAD_INSTRUCTION 异常,并且在命令行上 运行ning 它与 sudo 产生崩溃(可能是同一个)

该行为似乎表明存在某种资源泄漏,但我还没有检测到。知道还有什么可能导致这种情况吗?

更新

我还没准备好宣布答案,但在用户将文件放入应用程序后,我的代码的不同部分开始出现这些权限错误。我注意到在日志的上方,我会看到如下消息:

Consume sandbox extension for itemIdentifier (1) from pasteboard failed!

追踪这个错误让我想到了其他人提出的问题:Sandboxed Mac app exhausting security scoped URL resources

不幸的是,accepted answer 说(释义)"tough noogies"。似乎 Cocoa 和沙盒机制本身正在泄漏安全范围令牌(尽管我无法使用符号断点进行验证并且不知道其他检查方法)。在对沙盒文件进行一定数量(未知)的文件操作后,您将开始收到此错误,唯一的解决办法是退出并重新启动。

我希望至少有一些方法可以在关闭时提示用户重新启动,但我不确定是否有任何方法可以衡量这些句柄中有多少正在使用。或者,更好的是,如果我可以在处理完删除的文件后手动清理,但我不确定这将如何工作,因为我需要使用 NSFilenamesPboardType 粘贴板类型来获取多个文件的路径。我尝试从这些创建 NSURLs 并停止安全范围访问,但这没有效果。

更新 2

我为此提交了 DTS 票证,因为它影响了用户并且没有明确的解决方法。当我发现更多时,我会更新问题(也许会给出答案?)。

苹果DTS团队的回应

显然,这是一个已知问题,没有可用的解决方法。我提交了雷达:rdar://20652066,如果你想欺骗它。

这已在 El Capitan (10.11) 版本中修复(可能是第一个,但我不确定)。当我根据更新后的 SDK 构建我的应用程序时,行为恢复正常。