-3
\$\begingroup\$

I saw this post.

Is this a good implementation of malloc using mmap?

memory.hpp

#ifndef MEMORY_HPP
#define MEMORY_HPP

void *malloc(unsigned int);
void *calloc(unsigned int);
void free(void *);

#endif

memory.cpp

// https://stackoverflow.com/questions/33791310/c-mmap-initialize-at-0xffffffff
// https://stackoverflow.com/questions/8475609/implementing-your-own-malloc-free-with-mmap-and-munmap
#include "memory.hpp"
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>

void *malloc(unsigned int size)
{
    unsigned int *plen;
    unsigned int len = size + sizeof(size); // Add sizeof( size ) for holding length.

    plen = (unsigned int *)mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_SHARED, -1, 0);

    if (plen == MAP_FAILED)
    {
        printf("map failed\n");
        return NULL;
    }

    *plen = len;               // First 4 bytes contain length.
    return (void *)(&plen[1]); // Memory that is after length variable.
}

void *calloc(unsigned int size)
{
    void *ptr = malloc(size);
    memset(ptr, 0, size);
    return ptr;
}

void free(void *ptr)
{
    if (ptr == NULL)
    {
        return;
    }
    unsigned int *plen = (unsigned int *)ptr - 1; // Get length variable.
    munmap(plen, *plen);
}


\$\endgroup\$
4
  • 3
    \$\begingroup\$ Is this your code or someone else's? Are you familiar with a standard implementation like dlmalloc? \$\endgroup\$
    – qwr
    May 26, 2022 at 21:23
  • 3
    \$\begingroup\$ You might want to read some of the answers on the questions on Stack Overflow you pointed to, for instance use size_t rather than unsigned int. The type size_t is what the sizeof() function returns. \$\endgroup\$
    – pacmaninbw
    May 26, 2022 at 21:43
  • 2
    \$\begingroup\$ This lacks a realloc(). And both malloc() and calloc() would be better off mapping copy-on-write pages from the /dev/zero device or equivalent than allocating pages and then overwriting them. \$\endgroup\$
    – Davislor
    May 27, 2022 at 4:06
  • 3
    \$\begingroup\$ Specifying both contradicting SHARE-flags is out of spec: Either MAP_SHARED or MAP_PRIVATE can be specified, but not both. \$\endgroup\$
    – greybeard
    May 27, 2022 at 5:09

2 Answers 2

2
\$\begingroup\$

Some limitations of this implementation include:

There is no realloc().

This implementation uses unsigned int rather than size_t, so it does not follow the Standard, and can only allocate 32 bits on most 64-bit implementations.

It passes a value of -1 as the file descriptor, which is not conformant to the POSIX standard.

For most applications, it would be better to map copy-on-write pages from a device like /dev/zero that only get mapped into physical memory if they are used than for calloc() to touch every page of memory and write zeroes to it. In addition to taking much more time, this will evict other pages of memory from your cache and cause cache misses when calloc() returns.

Although you are not required by the specification to have free() do any error-checking at all, it is a very bad idea to fail silently and leave the program in an unstable state.

Finally, although you know this already, real-world implementations of malloc() only use this scheme for large allocations, and allocate smaller blocks from a heap.

\$\endgroup\$
2
\$\begingroup\$

Alignment requirements not certainly met.

The standard library *alloc() functions return pointers that are "suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement". OP's code makes no provision for the returned pointer to be so aligned. Research max_align_t.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.