5

I'm trying to invoke one app from another in C++. The embedded app is subject to segmentation faults due to syntax errors from an input file, so the outer program would be responsible for re-running the inner, and logging failures.

My immediate idea was to rely on the return value of the inner program. So I started to experiment with that. I wrote a dummy program in Inner.cpp:

#include <iostream>

int main()
{
    std::cout << "Inner" << std::endl;
    return 22;
}

Then, I wrote this in Outer.cpp:

#include <cstdlib>
#include <iostream>

int main()
{
    int retval = system("~/Inner");
    std::cout << "Returned: " << retval << std::endl;   
    return 0;
}

Got this confusing output:

Inner
Returned: 5632

So I started reading. I soon found out, that only the 8 LS bits go through, which are treated unsigned. But wouldn't that only mean not to use values above 255? Why am I getting this strange value?

So I started looking at the bits.

What I expected: 22 -> 0000 0000 0000 0000 0000 0000 0001 0110
What I got:    5632 -> 0000 0000 0000 0000 0001 0110 0000 0000

Woah, that's the same pattern, just shifted. And indeed, when I modified my line to:

std::cout << "Returned: " << (retval >> 8) << std::endl;

I always got the exact number I wanted. However, I can't find anything on why is this happening, and now I'm concerned, that there are many more surprises when I get to the part where I'll need to detect a SIGSEGV in the inner program, and continue execution in the outer.

My question ultimately, is: What's the best way to safely embed one (command line) application in another, considering they need to communicate some minimal data, and the one being invoked might end up segfaulting? (Also, what is this bitshift thing with the return value?)

Ubuntu 12.04.4 LTS
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Innkeeper
  • 663
  • 1
  • 10
  • 22
  • 1
    Why not just fix the bugs in the embedded app so that it doesn't crash ? – Paul R May 15 '14 at 12:18
  • @PaulR There are no bugs. It works with huge input files coming from external source, there is no time to crawl and check for all the syntax errors before parsing. – Innkeeper May 15 '14 at 12:22
  • 1
    If the app crashes when it fails to handle a syntax error in the input file then I would call that a pretty serious bug. – Paul R May 15 '14 at 12:22
  • @PaulR I don't want an if statement before every value read from the files. I'd rather skip the whole file when the app crashes, and continue with the next file. But I'm not asking for advice on this issue, my question should be clear. – Innkeeper May 15 '14 at 12:26
  • @JohnnyMopp What about it? The bits I want are not on the other end, they are 8 bits away, in the middle. – Innkeeper May 15 '14 at 12:26
  • Note that `system` returns a status in `waitpid` format - you should use `WEXITSTATUS` to get the exit status from this. See the relevant man pages. – Paul R May 15 '14 at 12:29
  • @PaulR Yes, that explains it, thank you! I'm getting the same results with the macro. – Innkeeper May 15 '14 at 12:32
  • Also, is it possible that zero is returned from a segfaulting program? Or can I assume a good run if I get zero? – Innkeeper May 15 '14 at 12:40
  • 1
    I was trying to find the right words to describe exactly the quandary you just asked. If the invoked sub child does indeed segfault, it will terminate with a signal, not a clean exit status. Its been forever since I've done it (and it would be so here as well because I would rather fix the bug than rely on the unknown), but `WIFSIGNALED()` would seem likely to test if a signal condition castrated your child. Keep in mind SIGINT and SIGQUIT are ignored by `system()`. – WhozCraig May 15 '14 at 12:47

2 Answers2

2

You want to use fork, exec and wait, something like:

int status;
if ((pid = fork()) == 0) // child proc
     exec("~/Inner");
else // parent
    waitpid(-1, &status, 0)
Paul Evans
  • 27,315
  • 3
  • 37
  • 54
1

Use WEXITSTATUS

int retval = system("~/Inner");
retval = WEXITSTATUS(retval);

will do

Ari
  • 92
  • 5