Re: "broken pipe", but not when debugging...


Jack Brindle
 

A broken pipe usually means that one end of the connection has been closed for one reason or another. You don’t show the actual
read and write code, but that is most likely where the problem occurs. Be sure and put the data write into a try-catch block in order
to catch the broken pipe (assuming it occurs on a write). This is actually documented, but I’ll have to go find it to say. My notes indicate the
docs to say: This method raises an exception if the file descriptor is closed or is not valid, if the receiver represents an unconnected pipe
or socket endpoint, if no free space is left on the file system, or if any other writing error occurs. The catch block should set pretty much all the
handles to nil, especially the read handle.readabilityHandler. It is pretty easy and useful to set up the readabilityHandler block to get the
data coming from the executable.

This is a two-way street, and it is likely the other end is participating in the broken pipe, if not actually throwing it. If your pipes are not set
up properly and it tries to write to its stdout, you will see this issue.

Also, it might be helpful to debug the son an El Capitan system where we still have a good logging system.

One thing that does look slightly strange is the way the arguments are set up. NSTask really would like for each item to be in a separate
entry (i.e. @[@“ponder”, @“off”, @“noise”, @“1000000”…]. I don’t know if it makes any difference, but is worth trying.

This stuff works pretty well, but there is a lot of opportunity to get broken pipes when one side shuts down for any reason, or simply
closes their side of the connection. Try-catch is definitely your friend here, on both sides of the connection.

- Jack

On Aug 10, 2017, at 4:12 PM, Graham Cox <graham@...> wrote:

Hi,

I’m using NSTask to ‘talk to’ a command line executable that is embedded in my app. I use NSPipe as its stdIn and stdOut channels.
When I run the code under Xcode, it works fine. When I build the app into a standalone executable, it fails with a “broken pipe 13” error message and immediate termination.

Aug 11 09:01:23 The-New-iMac com.apple.xpc.launchd[1] (net.apptree.checkmate.Checkmate.61324[49384]): Service exited due to signal: Broken pipe: 13 sent by Checkmate[49384]

The code seems pretty straightforward, so I can’t see anything tricky. Any ideas what could be causing this?


NSBundle* mainBundle = [NSBundle mainBundle];
NSString* executablePath = [mainBundle pathForAuxiliaryExecutable:@"crafty"];
NSString* resourcePath = [mainBundle resourcePath];

mCrafty = [[NSTask alloc] init];

mCrafty.launchPath = executablePath;
mCrafty.arguments = @[@"ponder off",@"noise 1000000",@"sn 10",@"sd 10"];

NSMutableDictionary* environment = [NSMutableDictionary dictionary];

[environment setObject:resourcePath forKey:@"CRAFTY_BOOK_PATH"];

mCrafty.environment = environment;

[self initStdIn];
[self initStdOut];

NSLog(@"launching crafty");

[mCrafty launch];




- (void) initStdIn
{
NSPipe* inputToCrafty = [NSPipe pipe];

mCrafty.standardInput = inputToCrafty;

NSLog(@"stdIn initialized");
}



- (void) initStdOut
{
NSPipe* craftyOutput = [NSPipe pipe];

craftyOutput.fileHandleForReading.readabilityHandler = ^(NSFileHandle* fileHandle)
{
//[all the stuff that parses the output deleted for clarity]
};

mCrafty.standardOutput = craftyOutput;

NSLog(@"stdOut initialized");
}


Note: For the standalone executable, I don’t see any of the logged (NSLog) messages. I’m not sure why. One difficulty is that the revised Console app makes it a lot harder to figure out what the hell I’m looking at. system.log contains the SIGPIPE error, but none of the log messages. Where did they go?

—Graham





Join {cocoa@apple-dev.groups.io to automatically receive all group messages.