macOS:删除文件时的断点



在我的旧macOS应用程序中,用Objective-C编写,我正在调试一个可重现的问题,其中文件包在系统框架调用期间过早被删除。 为了获得线索,我希望在删除文件时让调试器中断。 为此,我在 Xcode 中的这些符号处设置了符号断点:

unlink
unlinkat
-[NSFileManager removeItemAtPath:error:]
-[NSFileManager removeItemAtURL:error:]

所有这些断点都按预期解析为实际断点,当按预期删除文件时,它们会按预期中断。 但是在麻烦的过早文件删除期间,不会发生中断。

macOS 中是否有任何其他功能可以删除文件,我应该为其添加断点?

背景资料:

在我的自定义 NSDocument 子类中,当对新复制的文档包(如在文件>重复项中)但从未保存的文档包调用[super saveDocument]时,会出现此问题。 此类文档包驻留在~/Library/Autosave Information/中,当一切正常时,将保留在那里,直到"保存"面板出现,并随后被关闭。 但是,在错误情况下,当用户单击File > Save(或发生自动保存)时,包会立即消失,这显然会导致稍后的错误,指示已删除的包无法移动到保存面板返回的路径。

我还尝试将该包的 POSIX 权限更改为该包出现后,在单击"文件>保存"之前,更改为八进制 500。 这个想法是它无法删除,我还打开了我所有的异常和错误断点,希望神秘删除器会尖叫到调试器控制台。 结果:包未被删除,并且正如我所假设的那样,保存操作成功。 但什么都没有发出。 所以这个神秘删除器确实是问题所在,但显然既隐蔽又宽容:(

2019 年 7 月 19 日更新:

在5天寻找其他事情要做之后,我决定咬紧牙关,按照Ken Thomases的建议使用DTrace。 它起作用了,向我显示主题文件包中的所有文件都通过调用libsystem_kernel.dylib__unlink删除,而-[NSFileManager removeItemAtPath:error:]又调用了 .

我不知道为什么我在这些函数上的断点没有为这些调用中断,除了可能在堆栈跟踪的底部有一个线索,提到"xpc"。 此文件删除是否有可能由 XPC 帮助程序进程完成? DTrace 是否还会探测所探测进程的帮助程序进程? 那将是相当惊人的。

以下是 DTrace 会话的节略记录:

Air2 jk$ sudo dtrace -n 'syscall::unlink*:entry,syscall::rmdir:entry,syscall::rename:entry { printf("time=%d  arg=%sn", timestamp/1000000000, copyinstr(arg0)); ustack(100); }' -p `pgrep MyApp`
Password:
dtrace: description 'syscall::unlink*:entry,syscall::rmdir:entry,syscall::rename:entry ' matched 4 probes
CPU     ID                    FUNCTION:NAME
1    178                     unlink:entry time=6562  arg=/Users/jk/Library/Autosave Information/Unsaved MyApp Document.bmco
libsystem_kernel.dylib`__unlink+0xa
libremovefile.dylib`__removefile_tree_walker+0x147
libremovefile.dylib`removefile+0x99
Foundation`-[NSFilesystemItemRemoveOperation main]+0xba
Foundation`__NSOPERATION_IS_INVOKING_MAIN__+0x11
Foundation`-[NSOperation start]+0x2db
Foundation`-[NSFileManager removeItemAtPath:error:]+0x54
AppKit`__90-[NSDocumentController(NSInternal) _autoreopenDocumentsFromRecords:withCompletionHandler:]_block_invoke_2+0x90
AppKit`__89-[NSDocumentController reopenDocumentForURL:withContentsOfURL:display:completionHandler:]_block_invoke_2+0xa6
AppKit`___NSMainRunLoopPerformBlockInModes_block_invoke+0x19
CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__+0xc
CoreFoundation`__CFRunLoopDoBlocks+0x17b
CoreFoundation`__CFRunLoopRun+0xae8
CoreFoundation`CFRunLoopRunSpecific+0x1f3
HIToolbox`RunCurrentEventLoopInMode+0x124
HIToolbox`ReceiveNextEventCommon+0x164
HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter+0x40
AppKit`_DPSNextEvent+0x3de
AppKit`-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]+0x548
ViewBridge`-[NSViewServiceApplication nextEventMatchingMask:untilDate:inMode:dequeue:]+0x5f
AppKit`-[NSApplication run]+0x292
AppKit`NSApplicationMain+0x309
libxpc.dylib`_xpc_objc_main.cold.3+0x38
libxpc.dylib`_xpc_objc_main+0x203
libxpc.dylib`_xpc_copy_xpcservice_dictionary
ViewBridge`xpc_connection_handler
ViewBridge`NSViewServiceApplicationMain+0xbff
com.apple.appkit.xpc.openAndSavePanelService`main+0xc0
libdyld.dylib`start+0x1
com.apple.appkit.xpc.openAndSavePanelService`0x1

(该脚本中的调用显然试图取消文件包的链接,我认为这会失败,因为包不是空的。 接下来是几个类似的调用,这些调用遍历包树,删除每个节点,最后重复该调用以删除包,显然成功了。

更新 2019-AUG-06

虽然我们现在知道问题的低层次原因,但我们仍然不知道高级原因。 此后,我发现该问题(过早删除~/Library/Autosave Information中的临时文档文件)仅在macOS 10.15 Beta 4-5(当前版本)中发生,并且仅在应用程序在应用程序沙盒关闭的情况下构建时才发生。 当应用沙盒打开时,相关Autosave Information位于应用容器中的不同位置,因此这应该是一个很好的线索! 这个问题很容易通过一个小型演示应用程序重现,Core Data,基于文档,我已经把它和一个短视频一起提交给了苹果。 如果有人有苹果的电话,请把他们的注意力引向FB6937676!

重命名操作将使源路径不再引用文件(看起来像源路径中的文件已删除)。它还可以取消链接/删除目标路径上的文件,尽管它将替换为源路径上的文件。所以,那将是rename()renameat()renamex_np()renameatx_np()

当然,rmdir()可以删除目录,但前提是目录为空。

显然,有一个隐藏的delete()系统调用。它被描述为"使用Carbon语义从文件系统中删除名称"。框架可能正在使用它。

最新更新