Exception `-[NSConcreteFileHandle readDataOfLength:]: Bad file descriptor` when running a NSUserUnixTask

StackOverflow https://stackoverflow.com/questions/16637501

  •  29-05-2022
  •  | 
  •  

質問

I'm using NSUserUnixTask to run an unsandboxed NSTask on my sandboxed app. However, my code hangs on calls to [NSFileHandle readDataToEndOfFile]. If I remove those calls it works perfectly. If I replace [NSFileHandle readDataToEndOfFile] with [NSFileHandle availableData] it hangs as well.

Here is the code:

NSUserUnixTask* unixTask = [[NSUserUnixTask alloc] initWithURL: [NSURL fileURLWithPath: path] error: nil];

// Create error file handle
NSFileHandle* errorFH = [NSFileHandle fileHandleWithStandardError];
[unixTask setStandardError: errorFH];

// Create output file handle
NSFileHandle* outputFH = [NSFileHandle fileHandleWithStandardOutput];
[unixTask setStandardOutput: outputFH];

// Run task with termination handler
[unixTask executeWithArguments: nil completionHandler: ^(NSError* error2) {

    // Save output
    NSString* output = [[NSString alloc] initWithData: [outputFH readDataToEndOfFile] encoding: NSUTF8StringEncoding];
    if ([output length]) { // <-- Execution never reaches this line when the block is called
        NSLog(@"%@", output);
    }

    // Read error 1
    NSString* error1 = [[NSString alloc] initWithData: [errorFH readDataToEndOfFile] encoding: NSUTF8StringEncoding];
    if ([error1 length]) {
        NSLog(@"%@", error1);
    }

    // Read error 2
    if (error2) {
        NSLog(@"%@", error2);
    }
}];

Nothing is logged on Xcode's console, but if I open Console.app I see this line:

Warning: Exception caught during decoding of received reply to message 'executeScript:interpreter:arguments:standardInput:standardOutput:standardError::', dropping incoming message and calling failure block.

Exception: *** -[NSConcreteFileHandle readDataOfLength:]: Bad file descriptor

Hmmm, how can I solve this? Before I had my app sandboxed I used NSPipe in conjunction with NSTask and everything worked, but now NSUserUnixTask requires the use of NSFileHandle instead and I reckon my problem is simply because I'm not using it correctly. But still I have no idea what I'm doing wrong.

役に立ちましたか?

解決

It seems to me that you have to use NSPipe to read stderr and stdout from NSUserUnixTask in the same way it is done with NSTask.

I have tested it with a "/bin/ls" task and it produced the expected output:

NSPipe *outPipe = [NSPipe pipe];
NSPipe *errPipe = [NSPipe pipe];
NSString *path = @"/bin/ls";
NSUserUnixTask *unixTask = [[NSUserUnixTask alloc] initWithURL: [NSURL fileURLWithPath: path] error: nil];
[unixTask setStandardOutput:[outPipe fileHandleForWriting]];
[unixTask setStandardError:[errPipe fileHandleForWriting]];
[unixTask executeWithArguments:nil completionHandler:^(NSError *error) {
    NSString *output = [[NSString alloc] initWithData: [[outPipe fileHandleForReading] readDataToEndOfFile] encoding: NSUTF8StringEncoding];
    NSLog(@"stdout: %@", output);

    NSString *error1 = [[NSString alloc] initWithData: [[errPipe fileHandleForReading] readDataToEndOfFile] encoding: NSUTF8StringEncoding];
    NSLog(@"stderr: %@", error1);
}];
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top