Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using mmap() instead of malloc()

Tags:

c

malloc

mmap

I am trying to complete an exercise that is done with system calls and need to allocate memory for a struct *. My code is:

myStruct * entry = (myStruct *)mmap(0, SIZEOF(myStruct), PROT_READ|PROT_WRITE,
MAP_ANONYMOUS, -1, 0);

To clarify, I cannot use malloc() but can use mmap(). I was having no issues with this on Windows in Netbeans, now however I'm compiling and running from command line on Ubuntu I am getting "Segmentation Fault" each time I try to access it.

Is there a reason why it will work on one and not the other, and is mmap() a valid way of allocating memory in this fashion? My worry was I was going to be allocating big chunks of memory for each mmap() call initially, now I just cannot get it to run.

Additionally, the error returned my mmap is 22 - Invalid Argument (I did some troubleshooting while writing the question so the error check isn't in the above code). Address is 0, the custom SIZEOF() function works in other mmap arguments, I am using MAP_ANONYMOUS so the fd and offsetparameters must -1 and 0 respectively.

Is there something wrong with the PROT_READ|PROT_WRITE sections?

like image 945
Sean Kelly Avatar asked Oct 19 '16 08:10

Sean Kelly


2 Answers

You need to specify MAP_PRIVATE in your flags.

myStruct * entry = (myStruct *)mmap(0, SIZEOF(myStruct),
        PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

From the manual page:

The flags argument determines whether updates to the mapping are visible to other processes mapping the same region, and whether updates are carried through to the underlying file. This behavior is determined by including exactly one of the following values in flags:

You need exactly one of the flags MAP_PRIVATE or MAP_SHARED - but you didn't give either of them.

A complete example:

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

typedef struct
{
    int a;
    int b;
} myStruct;

int main()
{
    myStruct * entry = (myStruct *)mmap(0, sizeof(myStruct),
            PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

    if (entry == MAP_FAILED) {
        printf("Map failed.\n");
    }
    else {
        entry->a = 4;
        printf("Success: entry=%p, entry->a = %d\n", entry, entry->a);
    }
    return 0;
}

(The above, without MAP_PRIVATE of course, is a good example of what you might have provided as a an MCVE. This makes it much easier for others to help you, since they can see exactly what you've done, and test their proposed solutions. You should always provide an MCVE).

like image 188
davmac Avatar answered Nov 12 '22 18:11

davmac


The man page for mmap() says that you must specify exactly one of MAP_SHARED and MAP_PRIVATE in the flags argument. In your case, to act like malloc(), you'll want MAP_PRIVATE:

myStruct *entry = mmap(0, sizeof *entry,
                       PROT_READ|PROT_WRITE,
                       MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

(I've also made this more idiomatic C by omitting the harmful cast and matching the sizeof to the actual variable rather than its type).

like image 20
Toby Speight Avatar answered Nov 12 '22 16:11

Toby Speight