返回大值的 NSUserAppleScriptTask 从不调用 completionHandler
NSUserAppleScriptTask returning large value never calls completionHandler
我有一个 Objective-C 应用程序正在使用 NSUserAppleScriptTask 调用一些 Applescript。 applescript 是 return 一个可以改变大小的字符串。
它在字符串很短的情况下工作正常。然而,当它变得很长时,它开始无声地失败。如果它尝试 return 一个长度为 40,000 个字符的字符串,则永远不会调用 completionHandler
,并且永远不会打印字符串 returned ...
。没有消息到日志,没有消息到控制台。它只是从未被调用过。
30,000 个字符的字符串可以正常工作。我不确定精确的截止点在哪里。
有人以前看过这个吗?我可以更改 属性 或配置设置以增加此限制吗?还是我只需要放弃 NSUserAppleScriptTask?
代码
NSURL* scriptURL = [[NSBundle mainBundle] URLForResource:@"ApplescriptHelper" withExtension:@"scpt"];
NSError* error;
NSUserAppleScriptTask* task = [[NSUserAppleScriptTask alloc] initWithURL:scriptURL error:&error];
NSLog(@"created task %@, error %@", task, error);
/* CREATE APPLE EVENT */
// taken from https://www.objc.io/issues/14-mac/sandbox-scripting/
ProcessSerialNumber psn = {0, kCurrentProcess};
NSAppleEventDescriptor *target = [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber bytes:&psn length:sizeof(ProcessSerialNumber)];
NSAppleEventDescriptor *function = [NSAppleEventDescriptor descriptorWithString:@"test"];
NSAppleEventDescriptor *event = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite eventID:kASSubroutineEvent targetDescriptor:target returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
[event setParamDescriptor:function forKeyword:keyASSubroutineName];
/* END CREATE APPLE EVENT */
[task executeWithAppleEvent:event completionHandler:^(NSAppleEventDescriptor*resultEventDescriptor, NSError *error) {
NSLog(@"returned %@, error %@", resultEventDescriptor, error);
if (!resultEventDescriptor) {
NSLog(@"%s AppleScript task error = %@", __PRETTY_FUNCTION__, error);
} else {
NSLog(@"success")
}
}];
ApplescriptHelper.scpt
on test()
set str to ""
repeat 40000 times
set str to str & "x"
end repeat
return str
end fetchMusic
这看起来像是一个 Apple 漏洞。你应该提交一份报告。
运行 您的代码,osascript
停滞于以下调用图:
+ 2812 start (in libdyld.dylib) + 8 [0x7fff97a205b4]
+ 2812 exit (in libsystem_c.dylib) + 55 [0x7fff9157f403]
+ 2812 __cxa_finalize_ranges (in libsystem_c.dylib) + 345 [0x7fff9157f0ff]
+ 2812 std::__1::ios_base::Init::~Init() (in libc++.1.dylib) + 16 [0x7fff8f1ebd98]
+ 2812 std::__1::basic_ostream<char, std::__1::char_traits<char> >::flush() (in libc++.1.dylib) + 68 [0x7fff8f1e2f5a]
+ 2812 std::__1::__stdoutbuf<char>::sync() (in libc++.1.dylib) + 137 [0x7fff8f1ec30d]
+ 2812 fflush (in libsystem_c.dylib) + 40 [0x7fff9155c31c]
+ 2812 __sflush (in libsystem_c.dylib) + 87 [0x7fff9155c3c0]
+ 2812 _swrite (in libsystem_c.dylib) + 87 [0x7fff91563e96]
+ 2812 __write_nocancel (in libsystem_kernel.dylib) + 10 [0x7fff918e57ba]
我认为您 运行 喜欢 pipe buffer limit of 65536 bytes。
如果您使用 NSUserAppleScriptTask
使用的未记录的 osascript
参数,您将获得带有 16 字节 header 和 UTF-16
编码文本的原始 AppleEvent 输出。
repeat
循环中超过 32760
的任何内容都会导致此行为。 32760
* 2
+ 16
= 65536
.
我有一个 Objective-C 应用程序正在使用 NSUserAppleScriptTask 调用一些 Applescript。 applescript 是 return 一个可以改变大小的字符串。
它在字符串很短的情况下工作正常。然而,当它变得很长时,它开始无声地失败。如果它尝试 return 一个长度为 40,000 个字符的字符串,则永远不会调用 completionHandler
,并且永远不会打印字符串 returned ...
。没有消息到日志,没有消息到控制台。它只是从未被调用过。
30,000 个字符的字符串可以正常工作。我不确定精确的截止点在哪里。
有人以前看过这个吗?我可以更改 属性 或配置设置以增加此限制吗?还是我只需要放弃 NSUserAppleScriptTask?
代码
NSURL* scriptURL = [[NSBundle mainBundle] URLForResource:@"ApplescriptHelper" withExtension:@"scpt"];
NSError* error;
NSUserAppleScriptTask* task = [[NSUserAppleScriptTask alloc] initWithURL:scriptURL error:&error];
NSLog(@"created task %@, error %@", task, error);
/* CREATE APPLE EVENT */
// taken from https://www.objc.io/issues/14-mac/sandbox-scripting/
ProcessSerialNumber psn = {0, kCurrentProcess};
NSAppleEventDescriptor *target = [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber bytes:&psn length:sizeof(ProcessSerialNumber)];
NSAppleEventDescriptor *function = [NSAppleEventDescriptor descriptorWithString:@"test"];
NSAppleEventDescriptor *event = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite eventID:kASSubroutineEvent targetDescriptor:target returnID:kAutoGenerateReturnID transactionID:kAnyTransactionID];
[event setParamDescriptor:function forKeyword:keyASSubroutineName];
/* END CREATE APPLE EVENT */
[task executeWithAppleEvent:event completionHandler:^(NSAppleEventDescriptor*resultEventDescriptor, NSError *error) {
NSLog(@"returned %@, error %@", resultEventDescriptor, error);
if (!resultEventDescriptor) {
NSLog(@"%s AppleScript task error = %@", __PRETTY_FUNCTION__, error);
} else {
NSLog(@"success")
}
}];
ApplescriptHelper.scpt
on test()
set str to ""
repeat 40000 times
set str to str & "x"
end repeat
return str
end fetchMusic
这看起来像是一个 Apple 漏洞。你应该提交一份报告。
运行 您的代码,osascript
停滞于以下调用图:
+ 2812 start (in libdyld.dylib) + 8 [0x7fff97a205b4]
+ 2812 exit (in libsystem_c.dylib) + 55 [0x7fff9157f403]
+ 2812 __cxa_finalize_ranges (in libsystem_c.dylib) + 345 [0x7fff9157f0ff]
+ 2812 std::__1::ios_base::Init::~Init() (in libc++.1.dylib) + 16 [0x7fff8f1ebd98]
+ 2812 std::__1::basic_ostream<char, std::__1::char_traits<char> >::flush() (in libc++.1.dylib) + 68 [0x7fff8f1e2f5a]
+ 2812 std::__1::__stdoutbuf<char>::sync() (in libc++.1.dylib) + 137 [0x7fff8f1ec30d]
+ 2812 fflush (in libsystem_c.dylib) + 40 [0x7fff9155c31c]
+ 2812 __sflush (in libsystem_c.dylib) + 87 [0x7fff9155c3c0]
+ 2812 _swrite (in libsystem_c.dylib) + 87 [0x7fff91563e96]
+ 2812 __write_nocancel (in libsystem_kernel.dylib) + 10 [0x7fff918e57ba]
我认为您 运行 喜欢 pipe buffer limit of 65536 bytes。
如果您使用 NSUserAppleScriptTask
使用的未记录的 osascript
参数,您将获得带有 16 字节 header 和 UTF-16
编码文本的原始 AppleEvent 输出。
repeat
循环中超过 32760
的任何内容都会导致此行为。 32760
* 2
+ 16
= 65536
.