Why does spawned program exit code change when debugging?

assert, c, c++, exit-code, linux

Solution

The <sys/wait.h> header file contains macros for analyzing return codes.

To check the reason for exit, you can do something like this:

#include <stdio.h>
#include <sys/wait.h>

...

void run(const char *command)
{
    int retcode = system(command);

    if (WIFEXITED(retcode))
    {
        int status = WEXITSTATUS(retcode);
        if (status)
        {
            printf("Exited normally with FAILURE status of %d!\n", status);
        }
        else
        {
            printf("Exited normally with SUCCESS(0) status!\n");
        }
    }
    else if (WIFSIGNALED(retcode))
    {
        int signal = WTERMSIG(retcode);
        printf("Abnormal termination - program crashed or was aborted with signal %d\n", signal);
    }

}

See "man waitpid" for a description of these macros.

Problem

I have a C++ program that I'm using to test that another program doesn't crash. The parent code(we'll call it 'parentProg') looks something like this: ``` int run(const char * command) { ... int retCode = system(command); printf("Code is %d\n",retCode); if(retCode == 134) //128 + SIGABORT { // Record error conditions ... } } ``` The command variable contains the program being tested(we'll call it 'childProg'). With a previous Linux distribution, this code worked as expected. If a.out crashed or hit an assertion, it would return 134 and the error handling code would run. However after I upgraded to a newer Linux distribution this is no longer the case. Instead I see a return code of 6 when run as a spawned program, using GDB, or nemiver. Strangely, it reverts back to 134 if I run the child program alone, or using DDD. For the following tests I've modified childProg to be only the following code: ``` #include <assert.h> int main(int argc, char * argv[]) { assert(0); return 0; } ``` childProg by itself ``` [user@localhost multi]$ ./childProg childProg: temp.cpp:5: int main(int, char **): Assertion `0' failed. Abort [user@localhost multi]$ echo $? 134 ``` parentProg which spawns childProg ``` [user@localhost multi]$ ./parentProg 1 o Running 1 times childProg: temp.cpp:5: int main(int, char **): Assertion `0' failed. Code is 6 Done 0 [user@localhost multi]$ ``` With GDB ``` (gdb) run Starting program: parentProg 1 o Running 1 times Detaching after fork from child process 3311. childProg: temp.cpp:5: int main(int, char **): Assertion `0' failed. Code is 6 Done 0 [Inferior 1 (process 3295) exited normally] (gdb) ``` With DDD ``` (gdb) run 1 o Starting program: parentProg 1 o Running 1 times Detaching after fork from child process 3336. childProg: temp.cpp:5: int main(int, char **): Assertion `0' failed. Code is 134 Done 0 [Inferior 1 (process 3319) exited normally] (gdb) ``` This works as expected ``` [me@localhost multi]$ /bin/sh -c ./childProg childProg: temp.cpp:5: int main(int, char **): Assertion `0' failed. Abort [me@localhost multi]$ echo $? 134 ``` What could possibly be going on here? Is there a better way to check for crashing/segfaults/assertions other than checking the exit code?

Original source

Related problems