0

I disassembled a 7,838,304-Byte portion of /usr/lib/x86_64-linux-gnu/dri/i965_dri.so using Capstone as shown below:

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdlib.h>
#include <capstone/capstone.h>


#define MAX_DISAS_BYTES (0x8e0bb0 - 0x167150)
#define MAX_PATH_LEN 200

unsigned char code [MAX_DISAS_BYTES];

void disas()
{ 
    cs_insn *insns;
    int count;
    unsigned long fileOff = 0x167150;
    unsigned long addrOff = 0x167150;
    unsigned int size = (0x8e0bb0 - 0x167150);
    char fileName [MAX_PATH_LEN] = "/usr/lib/x86_64-linux-gnu/dri/i965_dri.so";
    if (size > (MAX_DISAS_BYTES))
    {
        printf("fn size too large (%d > %d)\n", size , (MAX_DISAS_BYTES));
        exit(1);
    }

    FILE *f = fopen(fileName, "rb");
    if (!f)
    {
        printf("fopen");
        exit(1);
    }

    if (fseek(f, fileOff, SEEK_SET) != 0)
    {
        printf("fseek");
        fclose(f);
        exit(1);
    }

    size_t n = fread(code, 1, MAX_DISAS_BYTES, f);
    fclose(f);

    csh handle;

    if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK)
    {
        printf(stderr, "Failed to initialize Capstone\n");
        exit(1);
    }

    // Enable detailed mode
    cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);

    count = cs_disasm(handle, code, size, addrOff, 0, &insns);

    // bad mallocs
    void *m1 = malloc(sizeof(cs_detail));
    void *m2 = malloc(sizeof(cs_detail));
    void *m3 = malloc(sizeof(cs_detail));
    void *m4 = malloc(sizeof(cs_detail));
    void *m5 = malloc(sizeof(cs_detail));
    // end of bad mallocs

    if (count > 0)
    {
        //for (size_t i = 0; i < count; i++)
        //{
        //    printf("0x%"PRIx64":\t%s\t%s\n", insns[i].address, insns[i].mnemonic, insns[i].op_str);
        //}

        printf("to free\n");
        sleep(5);
        cs_free(insns, count);
        printf("freed\n");
        sleep(5);
    }
    else 
    {
        printf("Failed to disassemble bytes at offset 0x%lx\n", fileOff);
        exit(1);
    }

    cs_close(&handle); 
}

int main()
{
    disas();
    return 0;
}

The problem is when I add the five malloc() calls marked as // bad mallocs, a huge portion of memory becomes unfreeable.

Precisely, before executing the program, on printf("to free\n"); and on printf("freed\n");, the system RSS is 2.8 GB, 6.28 GB and 5.86 GB, respectively.

Hence, almost 3 GB of memory is unfreeable. Note that, removing bad mallocs or freeing them before calling cs_free(), avoids this situation and cs_free() can release this extra memory. Why do five small dynamic allocations cause a huge amount of memory unfreeable? Any hint is appreciated.

1 Answer 1

0

Glibc dynamic allocator seemingly uses aggressive caching. When the application allocates huge amounts of memory and frees them, sometimes (e.g., when I place five bad mallocs before calling for release), the allocated chunks are not returned to the OS. Therefore, I had to use the following function to free them explicitly:

Otherwise, in many cases the Linux OOM Killer would be activated to kill the process. The glibc dynamic allocator has no information about the system-level memory shortage and at the same time the OS does not realize that gigabytes of process pages are actually unused. Hence, the process will be punished severely.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.