D
D
dariasweetsun2021-07-28 18:57:01
linux
dariasweetsun, 2021-07-28 18:57:01

Different address space for child and parent process (fork, mmap)?

There are actually two questions here (but they are related).

Question #1:
I can't figure out why a variable that was declared before the fork() call (that is, in the parent process) has the same address in the child process. Although, as far as I know, the child process will have its own virtual address space and, accordingly (as I understand it), that variable should have a different address, but this is not so. However, everything works as if they are really isolated from each other (changes in the child are not visible in the parent)

Question #2:
Why, when using munmap() in a child process (before it terminates), in the parent process, it is still possible to access and change the contents of the "mapped" memory ??? (There is a guess that this will be related to the answer to the first question).

Program code:

#include <iostream>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>

int main(int argc, char* argv[])
{
    void* shared = mmap(NULL, sizeof(int), PROT_READ |  PROT_WRITE, 
                        MAP_SHARED | MAP_ANONYMOUS, -1, 0);
    
    int* sharedValue = static_cast<int*>(shared);

    *sharedValue = 0;
    std::cout << "before forks sharedValue: " << sharedValue << '\n';
    std::cout << "before forks *sharedValue: " << *sharedValue << '\n';

    int value = 0;
    std::cout << "before forks &value: " << &value << '\n';
    std::cout << "before forks value: " << value << '\n';
    
    int parentpid = getpid();
    int childpid;
    for(int i = 0; i < 2; ++i)
    {
        int forkret = fork();
        switch (forkret)
        {
        case -1:
            std::cerr << "Fork failed...\n";
            exit(EXIT_FAILURE);
        
        case 0:
            childpid = getpid();
            std::cout << "Child: pid " << childpid << '\n';
            std::cout << "child &value: " << &value << '\n';
            std::cout << "child value: " << value << '\n';
            std::cout << "child sharedValue: " << sharedValue << '\n';
            std::cout << "child *sharedValue: " << *sharedValue << '\n';
            value = childpid;
            *sharedValue = childpid;
            std::cout << "child value = pid: " << value << '\n';
            std::cout << "child *sharedValue = pid: " << value << '\n';
            munmap(sharedValue, sizeof(int));
            std::cout << "child munmap() called\n";
            exit(EXIT_SUCCESS);

        default:
            std::cout << "Parent: pid " << parentpid << '\n';
            wait(0);
            std::cout << "Child terminated\n";
            std::cout << "parent &value: " << &value << '\n';
            std::cout << "parent value: " << value << '\n';
            std::cout << "parent sharedValue: " << sharedValue << '\n';
            std::cout << "parent *sharedValue: " << *sharedValue << '\n';
            value = parentpid;
            *sharedValue = parentpid;
            std::cout << "parent value = pid: " << value << '\n';
            std::cout << "parent *sharedValue = pid: " << value << '\n';
        }
    }
    std::cout << "Parent terminated\n";
    return 0;
}


Console output:
before forks sharedValue: 0x7ffff7ffb000
before forks *sharedValue: 0
before forks &value: 0x7fffffffdc74
before forks value: 0
Parent: pid 18027
Child: pid 18034
child &value: 0x7fffffffdc74
child value: 0
child sharedValue: 0x7ffff7ffb000
child *sharedValue: 0
child value = pid: 18034
child *sharedValue = pid: 18034
child munmap() called
Child terminated
parent &value: 0x7fffffffdc74
parent value: 0
parent sharedValue: 0x7ffff7ffb000
parent *sharedValue: 18034
parent value = pid: 18027
parent *sharedValue = pid: 18027
Parent: pid 18027
Child: pid 18035
child &value: 0x7fffffffdc74
child value: 18027
child sharedValue: 0x7ffff7ffb000
child *sharedValue: 18027
child value = pid: 18035
child *sharedValue = pid: 18035
child munmap() called
Child terminated
parent &value: 0x7fffffffdc74
parent value: 18027
parent sharedValue: 0x7ffff7ffb000
parent *sharedValue: 18035
parent value = pid: 18027
parent *sharedValue = pid: 18027
Parent terminated

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Armenian Radio, 2021-07-28
@dariasweetsun

This special, cow magic (CoW, Copy On Write)
fork simply marks the pages of the parent as CoW and immediately starts the child. Real copying will happen only if the descendant will write something there.
The second question - the shared memory already belongs to two processes individually, so if one has closed the descriptor, the second does not care about it.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question