Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory not requested being allocated

Tags:

c

memory

I have written a simple memory allocator, basically creates a chain of allocated blocks, they are linked together using pointers stored in a metadata struct before the allocated area.

The code works perfectly, and I am able to allocate chain of blocks of size sz which are then freed with another function written by me.

The problem is that I noticed, using vmmap command, that apparently memory is being allocated by malloc without explicitly requesting it. Here's a paste of various vmmap, taken at different point of the program execution:

## before first alloc
# this has been taken before any allocation happens in the code.

REGION TYPE                      VIRTUAL
===========                      =======
Kernel Alloc Once                     4K
MALLOC                             9388K        see MALLOC ZONE table below
MALLOC (admin)                       24K
STACK GUARD                        56.0M
Stack                              8192K
VM_ALLOCATE                           8K <-- we start with 8K
__DATA                              668K
__LINKEDIT                         70.2M
__TEXT                             5860K
shared memory                         4K
===========                      =======
TOTAL                             149.8M

                                 VIRTUAL ALLOCATION      BYTES
MALLOC ZONE                         SIZE      COUNT  ALLOCATED  % FULL
===========                      =======  =========  =========  ======
DefaultMallocZone_0x10ad37000      9216K        363        27K      0%

=======================================================================

## after first alloc
# this is after the chain allocation.

REGION TYPE                      VIRTUAL
===========                      =======
Kernel Alloc Once                     4K
MALLOC                             18.2M <-- why the hell does malloc() increase?
MALLOC (admin)                       24K
STACK GUARD                        56.0M
Stack                              8192K
VM_ALLOCATE                        8200K <-- this is expected, we allocate memory with vm_allocate()
__DATA                              668K
__LINKEDIT                         70.2M
__TEXT                             5860K
shared memory                         4K
===========                      =======
TOTAL                             166.8M

                                 VIRTUAL ALLOCATION      BYTES
MALLOC ZONE                         SIZE      COUNT  ALLOCATED  % FULL
===========                      =======  =========  =========  ======
DefaultMallocZone_0x10ad37000      18.0M        364        31K      0%

=======================================================================

## after chain release

REGION TYPE                      VIRTUAL
===========                      =======
Kernel Alloc Once                     4K
MALLOC                             19.2M <-- malloc increases even more?!?
MALLOC (admin)                       24K
STACK GUARD                        56.0M
Stack                              8192K
VM_ALLOCATE                           8K <-- after chain release
__DATA                              668K
__LINKEDIT                         70.2M
__TEXT                             5860K
shared memory                         4K
===========                      =======
TOTAL                             159.8M <-- but why has total size increased?

                                 VIRTUAL ALLOCATION      BYTES
MALLOC ZONE                         SIZE      COUNT  ALLOCATED  % FULL
===========                      =======  =========  =========  ======
DefaultMallocZone_0x10ad37000      19.0M        364        31K      0%

I am on OS X and I use the vm_allocate routine to allocate memory for my blocks. So, as expected, the VM_ALLOCATE section in vmmap shows that after the chain release, the section memory returns to initial size, i.e. 8K. I never call malloc in my code.

But apparently, the MALLOC section size increases after the allocation! And it never frees. The total size, after the chain release is 10MB more than before the chain allocation.

Has anyone idea of why could this happen? I don't think that the vm_allocate routine calls malloc, that wouldn't make sense. Thanks in advance for any help!

Testing without allocating code

I actually commented out all the allocating code that my program did, basically left an empty main function. Then repeated the three vmmap checks for my program. Results:

REGION TYPE                      VIRTUAL
===========                      =======
Kernel Alloc Once                     4K
MALLOC                             9388K        see MALLOC ZONE table below
MALLOC (admin)                       24K
STACK GUARD                        56.0M
Stack                              8192K
VM_ALLOCATE                           8K
__DATA                              668K
__LINKEDIT                         70.2M
__TEXT                             5860K
shared memory                         4K
===========                      =======
TOTAL                             149.8M

                                 VIRTUAL ALLOCATION      BYTES
MALLOC ZONE                         SIZE      COUNT  ALLOCATED  % FULL
===========                      =======  =========  =========  ======
DefaultMallocZone_0x105379000      9216K        363        27K      0%

=========================================================================

REGION TYPE                      VIRTUAL
===========                      =======
Kernel Alloc Once                     4K
MALLOC                             10.2M        see MALLOC ZONE table below
MALLOC (admin)                       24K
STACK GUARD                        56.0M
Stack                              8192K
VM_ALLOCATE                           8K
__DATA                              668K
__LINKEDIT                         70.2M
__TEXT                             5860K
shared memory                         4K
===========                      =======
TOTAL                             150.8M

                                 VIRTUAL ALLOCATION      BYTES
MALLOC ZONE                         SIZE      COUNT  ALLOCATED  % FULL
===========                      =======  =========  =========  ======
DefaultMallocZone_0x105379000      10.0M        363        27K      0%

=========================================================================

REGION TYPE                      VIRTUAL
===========                      =======
Kernel Alloc Once                     4K
MALLOC                             11.2M        see MALLOC ZONE table below
MALLOC (admin)                       24K
STACK GUARD                        56.0M
Stack                              8192K
VM_ALLOCATE                           8K
__DATA                              668K
__LINKEDIT                         70.2M
__TEXT                             5860K
shared memory                         4K
===========                      =======
TOTAL                             151.8M

                                 VIRTUAL ALLOCATION      BYTES
MALLOC ZONE                         SIZE      COUNT  ALLOCATED  % FULL
===========                      =======  =========  =========  ======
DefaultMallocZone_0x105379000      11.0M        363        27K      0%

VM_ALLOCATE region now doesn't increase, as expected, no one is calling vm_allocate. But, as you can see, the MALLOC region still increases! Even without my code. It does grow less than before, i.e. 11MB instead of 18MB.

This means that my code has some direct influence on it, but what could it be? Maybe library functions are calling malloc? I use some printf in my allocating code, and I know functions like printf call malloc, but why then the is memory not released?

EDIT - Adding my code

Sorry for not including it before, and sorry if it is a total mess, I have written this in around two hours and it's my first attempt at creating a custom allocator.

#include <mach/mach.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc/malloc.h>

#define BLOCK_NO 2048

typedef struct mem_block {
    struct mem_block *next;
    unsigned int sz;
    unsigned int free:1;
} mem_block_t;

void *alloc_block(vm_size_t size)
{
    void *block_addr=NULL;
    mem_block_t metadata;
    vm_address_t *start_addr=0;

    vm_allocate(mach_task_self_, (vm_address_t*)&start_addr, size, 1);
    block_addr=(start_addr);
    metadata.next=(void*)NULL;
    metadata.sz=(unsigned int)size;
    metadata.free=0x0;

    memcpy(block_addr, (mem_block_t*)&metadata, sizeof(mem_block_t));

    return block_addr+sizeof(mem_block_t);
}

void dealloc_block(void *block_addr)
{
    unsigned int sz=0;
    vm_address_t start_addr = (vm_address_t)block_addr-sizeof(mem_block_t);
    memcpy(&sz, (void*)start_addr+sizeof(mem_block_t*), sizeof(sz));
    vm_deallocate(mach_task_self_, start_addr, sz);
}

void *alloc_block_chain(unsigned int blocks, vm_size_t size)
{
    void *head=NULL, *old_block=NULL, *curr=NULL;
    head = alloc_block(size);
    old_block = head;
    for (int i=0; i<blocks-1; i++) {
        curr = alloc_block(size);
        ((mem_block_t*)old_block)->next=curr;
        old_block=curr;
    }

    return head;
}

void dealloc_block_chain(void *block_addr_start)
{
    int cnt=0;
    void *curr=NULL, *old_block=NULL;
    curr=block_addr_start;
    while(1) {
        if (old_block) {
            dealloc_block(old_block);
            malloc_printf("dealloc'd block #%d: %p\n", cnt, old_block);
            cnt++;
        }
        if (!((mem_block_t*)curr)->next) {
            dealloc_block(curr);
            malloc_printf("dealloc'd final block: %p\n", curr);
            break;
        } else {
            old_block = curr;
            curr=((mem_block_t*)curr)->next;
        }
    }
}

int main(int argc, const char * argv[]) {

    system("read -n 1 -s -p \"Press any key to continue...\";echo");

    void *start = alloc_block_chain(BLOCK_NO, PAGE_SIZE);
    void *curr=start;

    for (int i=0; i<BLOCK_NO; i++) {
        malloc_printf("block #%d: %p\n", i, curr);
        curr = ((mem_block_t*)curr)->next;
    }

    system("read -n 1 -s -p \"Press any key to continue...\";echo");

    dealloc_block_chain(start);

    system("read -n 1 -s -p \"Press any key to continue...\";echo");

    return 0;
}

Possible solution

You can see I use malloc_printf in the code. I previously called printf there. The malloc_printf function is similar to printf but avoids calling malloc.

This seems to fix the leak! I will do more testing later, but for what I have seen the problem could indeed be OS X implementation of printf.

like image 310
jndok Avatar asked Aug 15 '15 13:08

jndok


People also ask

How do I allocate more RAM to downloads?

Allow Windows 10 to Allocate More RAMSelect Advanced system settings > Settings. Under the Visual Effects tab, there are four options. Select the Adjust for best performance option. After you do this, click Apply.

What happens if new fails to allocate memory?

Operator new can fail In the above example, if new fails to allocate memory, it will return a null pointer instead of the address of the allocated memory. Note that if you then attempt indirection through this pointer, undefined behavior will result (most likely, your program will crash).

How do you free the allocated memory?

The free() function is used to free the memory which is allocated previously using malloc() or calloc(). Syntax: free(mem_ptr);


1 Answers

The vm_deallocate function deallocates a region of virtual memory in the specified task's address space. The region starts at the beginning of the virtual page containing address and ends at the end of the virtual page containing address + size - 1. Because of this rounding to virtual page boundaries, the amount of memory deallocated may be greater than size. I think references wont be cleared and this is why other threads can still reference to this address space.if you run the mentioned program continuously it may lead to crash as well as the reference should also needs to be cleared. Correct me if I am wrong.

like image 171
Rajavelu Prabhu Avatar answered Oct 11 '22 23:10

Rajavelu Prabhu