Search code examples
c++bashpopenbroken-pipe

Why does initializing a file pointer inside a try block cause a broken pipe?


I have a bash script which I'm reading the results from in my program. Ptr is a simple popen() wrapper.

bool getResult(const char* path){
  Ptr f(path);
  char buf[1024];
  while (fgets(buf, sizeof(buf), f) == 0) {
    if(errno == EINTR)
      continue;
    log.error("Error (%d) : %s",errno,path);
    return false;
  }
  ...
  return true;
}

This works fine, but Ptr f(path) is not exception safe, so I replace it with:

Ptr f; // empty constructor, does nothing
char buf[1024];
try{
  Ptr f(path);
}catch(Exception& e){
  vlog.error("Could not open file at %s",path);
  return false;
}

When run (and the file exists) I get the following error:

/etc/my_script: line 165: echo: write error: Broken pipe

That line of the script is just:

echo $result

What is going on?


Solution

  • When you call Ptr f(path) in the try block, you're creating a whole new variable called f, that will be destroyed when you exit the try block.

    Then any code that uses f outsidde the try block will be using the uninitialised F that you created at the start.

    You have 2 options I can see:

    Add an Open method or similar to Ptr and call that from within the try block, or perhaps wrap all your file reading/writing code in the try block, that way you can avoid the need for returning false, as all the code will have been skipped when an exception was thrown.

    Option 1:

    Ptr f;
    try
    {
        f.Open( file );
    }
    catch
    ....
    

    Option 2:

    try
    {
        Ptr f( file );
        f.read();
    }
    catch
    .....