目标C命令在运行OSX Cron时失败



我已经编写了一个独立的Objective C命令应用程序。如果我通过LaunchDaemon运行它,那么当通过DistriuteObjects通信由ObjC客户端应用程序连接时,它运行得很好。如果我在命令行运行它,它运行得很好。如果我在Bash脚本调用时运行它,它运行得很好。然而,我尝试通过根用户的crontab以各种方式运行它,它会生成一个关于指针分配的崩溃报告:

Apr 14 05:27:00 volomike cron[72531]: cron(72531,0x7fff7d2fa000) malloc: *** error for object 0x7fb9c8400213: pointer being freed was not allocated
    *** set a breakpoint in malloc_error_break to debug
Apr 14 05:27:00 volomike diagnosticd[70689]: error evaluating process info - pid: 72531, puniqueid: 72531
Apr 14 05:27:00 volomike com.apple.xpc.launchd[1] (com.vix.cron[72531]): Service exited due to signal: Abort trap: 6
Apr 14 05:27:00 volomike com.apple.xpc.launchd[1] (com.apple.ReportCrash.Root[72550]): Endpoint has been activated through legacy launch(3) APIs. Please switch to XPC or bootstrap_check_in(): com.apple.ReportCrash.DirectoryService
Apr 14 05:27:00 volomike ReportCrash[72550]: Saved crash report for cron[72531] version 39 to /Library/Logs/DiagnosticReports/cron_2016-04-14-052700_volomike.crash

事故报告的重要部分写道:

Crashed Thread:        0  Dispatch queue: com.apple.main-thread
Exception Type:        EXC_CRASH (SIGABRT)
Exception Codes:       0x0000000000000000, 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY
Application Specific Information:
abort() called
*** error for object 0x7fb9c8400213: pointer being freed was not allocated

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib          0x00007fff9490ff06 __pthread_kill + 10
1   libsystem_pthread.dylib         0x00007fff9c45e4ec pthread_kill + 90
2   libsystem_c.dylib               0x00007fff9345b6e7 abort + 129
3   libsystem_malloc.dylib          0x00007fff9c02f041 free + 425
4   cron                            0x000000010367aa41 0x103677000 + 14913
5   cron                            0x000000010367a7e4 0x103677000 + 14308
6   cron                            0x0000000103679572 0x103677000 + 9586
7   cron                            0x000000010367925a 0x103677000 + 8794
8   cron                            0x000000010367885e 0x103677000 + 6238
9   libdyld.dylib                   0x00007fff949835ad start + 1

通过各种方式,我使用了这些不同的cron行,但它们在尝试调用命令时会立即崩溃,即使NSLog()从main的开始到应用程序的结束一直在向/var/log/system.log写入内容,也没有写入任何内容——就像当cron尝试调用我的命令时,它会立即死亡,并显示一个关于指针分配的崩溃报告。

41 5 * * * /bin/bash '/Applications/My App.app/Contents/Resources/mytoolcommand.sh' /q /sched
41 5 * * * /bin/bash '/Applications/My App.app/Contents/Resources/mytoolcommand.sh' /q /sched &
41 5 * * * '/Applications/My App.app/Contents/Resources/mytoolcommand' /q /sched
41 5 * * * '/Applications/My App.app/Contents/Resources/mytoolcommand' /q /sched &

再次注意,如果我执行'/Applications/My App.app/Contents/Resources/mytoolcommand.sh' /q /sched,它运行得很好,/bin/bash '/Applications/My App.app/Contents/Resources/mytoolcommand.sh' /q /sched'/Applications/My App.app/Contents/Resources/mytoolcommand' /q /sched 也是如此

我甚至做了一个变体,cron调用了我的mytoolcommand.sh脚本,并简单地将Hello World写入/tmp/out.txt,它运行得很好。所以,我知道我的crontab正在工作。

你能帮我弄清楚我做错了什么吗?一些可疑的可能问题:

  • 也许OSX El Capitan出于某种原因关闭了我的应用程序,比如没有正确签名。(我现在正在调试。我以前从未遇到过签名问题,除非它处理.app文件夹。此外,我可以从命令行运行它,而不会出现签名警告。)

  • 我马上就从main()加载了调试消息。他们应该写入/var/log/system.log,但事实并非如此。这告诉我应用程序在被cron调用时会立即崩溃。那么,我是否需要将一些特殊的东西加载到应用程序的库中,以便在cron下调用时正常运行?

发展

我怀疑El Capitan Gatekeeper可能是原因。因此,我在main.mm文件中创建了一个简单的Objective C控制台应用程序,并进行了编译。

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSString *sTest = @"Hello World";
        [sTest writeToFile:@"/tmp/test.txt" atomically:YES encoding:NSUTF8StringEncoding error:nil];
    }
    return 0;
}

克朗似乎处理得很好,所以看起来不像是守门员的问题。

我把这个问题解决了,但只是暂时的。我在一个全新的项目中重新编译了这个项目,复制了源代码和设置。然后,我通过cron运行了大约4次命令,没有出现任何问题。然而,当我第五次运行时,它再次失败,并继续失败。

所以,我想我必须弄清楚如何将其转换为LaunchAgent。

答案是你不会。对于您正在编码的应用程序,您不再在OSX上使用cron。相反,切换到LaunchAgent。当然,苹果为了支持POSIX而保留了它,因此可能会保留很长一段时间,但即使是他们的网站也鼓励人们不再使用cron进行应用程序编码。

"注意:尽管仍然支持cron,但不建议使用它解决方案有人反对使用launchd"

来源:https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/ScheduledJobs.html

不幸的是,LaunchAgents(至少在10.11.4中)还不支持cron风格的语法。(是的,我已经为你向苹果公司提交了这个建议。)所以,没有使用破折号、逗号或反斜杠。相反,它只支持一个整数和多个块来创建每个时间框架。如果这还不够合适,那么至少设置最短的时间框架,然后在你启动的任何程序中执行其余的代码,这样,例如,如果你只想在本月的第一个星期一运行某些程序,LaunchDaemon会在前七天启动,但如果不是本月的第一个星期一,你的应用程序会关闭。

最新更新