Search code examples
cmemory-managementbinarygdbposix

Execution Flow of Child and Parent


After reading on the web that i can't really determine which process runs before i.e child or parent I planned to disable the ASLR on my PC and run debugger to see if i can generate the pattern of execution, the observations I made are below with a GitGist to the GDB disas (full) along with the source code

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
fork();
//fork();
printf("LINUX\n");
//printf("my pid is %d",(int) getpid());
fork();
printf("REDHAT\n");
//printf("my pid is %d",(int) getpid());

//fork();
return 0;
}

this is the code i am talking about when i disas it in gdb it gave me:-

gdb-peda$ disas main
Dump of assembler code for function main:
   0x000000000000068a <+0>: push   rbp
   0x000000000000068b <+1>: mov    rbp,rsp
   0x000000000000068e <+4>: call   0x560 <fork@plt>
   0x0000000000000693 <+9>: lea    rdi,[rip+0xaa]        # 0x744
   0x000000000000069a <+16>:    call   0x550 <puts@plt>
   0x000000000000069f <+21>:    call   0x560 <fork@plt>
   0x00000000000006a4 <+26>:    lea    rdi,[rip+0x9f]        # 0x74a
   0x00000000000006ab <+33>:    call   0x550 <puts@plt>
   0x00000000000006b0 <+38>:    mov    eax,0x0
   0x00000000000006b5 <+43>:    pop    rbp
   0x00000000000006b6 <+44>:    ret    
End of assembler dump.

so basically it gives me a set pattern of the execution, so i think that should mean the program should execute always in a particular order i tried disas main about 3 times to see if the order actually ever changes and it does not but when i finally run the binary that's generated it gives me different outputs

root@localhost:~/os/fork analysis# ./forkagain
LINUX
REDHAT
LINUX
REDHAT
REDHAT
REDHAT
root@localhost:~/os/fork analysis# ./forkagain
LINUX
LINUX
REDHAT
REDHAT
REDHAT
REDHAT

which is inconsistent to the observation that i made in the disas, can someone please fill up the gaps in my understanding?

Fork Analysis Full


Solution

  • i tried disas main about 3 times to see if the order actually ever changes

    The order is fixed at compile time, so it can never change without you recompiling the program.

    In addition, the order is fixed by your program source -- the compiler is not allowed to re-order your output.

    What you observe then is the indeterminism introduced by the OS as a result of calling fork -- after the fork there are no guarantees which process will run first, or for how long. The parent may run to completion, then the child. Or the child may run to completion first. Or they may both run with time-slicing, say one line at a time.

    In addition, most non-ancient Linux systems today are running on multi-processor machines, and the two independent processes can run simultaneously after the fork.

    An additional complication is that your program is not well-defined, because of stdio buffering. While you see 6 lines of output, it might be hard for you to explain this result:

    ./forkagain | wc -l
    8
    ./forkagain > junk.out; cat junk.out
    LINUX
    REDHAT
    LINUX
    REDHAT
    LINUX
    REDHAT
    LINUX
    REDHAT
    

    You should add fflush(stdout); before fork to avoid this complication.

    P.S. You should also un-learn the bad habit of running as root -- sooner or later you'll make a stupid mistake (like typing rm -rf * in the wrong directory), and will be really sorry you did it as root.