Writing trash for free / delete

One of the problems with dynamic memory allocation is that you can delete/ freeblock the memory and still have pointers pointing to it. When someone searches for one of these pointers, there is a chance that something might “work”, but leave it vulnerable to memory corruption, etc.

To help with these problems, some make delete/ platforms freewrite garbage (something like DEDEDEDE) to a freed heap cell before releasing it as a freed cell. This means that when someone tries to dereference a pointer to a freed cell, one can more or less always expect a data_abort exception, which should lead to a program crash. This will be when using the debug library. The release library does not do this due to performance reasons.

Can someone tell me if this behavior can be obtained on standard Linux platforms using glibc or how to perform some simple operation for this. I think this will help me find some errors much easier.

I would like to add that to enable or disable this behavior for different assemblies should be trivial. The closest I can think of is malloc hooks, unfortunately, it does not accept cell size as a parameter for free.

+3
source share
7 answers

The following code does exactly what I want:

#include <malloc.h>

typedef void (*free_hook_t)(void*, const void*);

static free_hook_t system_free_hook;

static void my_free_hook (void *ptr, const void *caller)
     {
       __free_hook = system_free_hook;
       int size = malloc_usable_size(ptr);
       memset(ptr,0xDE, size);
       free (ptr);
       __free_hook = my_free_hook;
     }

static void init_free_hook()
     {
     system_free_hook = __free_hook;
      __free_hook = my_free_hook;
     }

/* Override initializing hook from the C library. */
void (*__malloc_initialize_hook) (void) = init_free_hook;

It is completely isolated, so it can technically be turned on or not as needed. The bit that I was missing is a feature malloc_usable_size.

Testing on Ubuntu 10.10, this also works in C ++, where you use newanddelete

+1
source

For C ++, you can do this quite portable: replace global operators ::newand ::delete:

#include <cstdlib>
#include <stdexcept>

// value must be at least as big as sizeof(size_t),
// and a multiple of the maximum alignment required for any
// type by this implementation
#define MAX_ALIGN 8

size_t &stored_size(char *p) {
    return *reinterpret_cast<size_t*>(p);
}

void *operator new(size_t n) {
    char *p = static_cast<char*>(std::malloc(n+MAX_ALIGN));
    if (!p) throw std::bad_alloc();
    stored_size(p) = n;
    char *base = p + MAX_ALIGN;
    // set base with n bytes of eye-catchers for uninitialized memory
    return base;
}

void operator delete(void *ptr) {
    if (!ptr) return;
    char *base = static_cast<char*>(ptr);
    char *p = base - MAX_ALIGN;
    size_t n = stored_size(p);
    // set base with n bytes of eye-catchers for freed memory,
    // and make sure your compiler isn't clever enough to optimize that away.
    std::free(p);
}

, ::new.

malloc/free, Linux , , , free hook, , t , malloc.

+3

. , .

+2

man malloc Linux:

   Recent  versions  of  Linux  libc  (later  than 5.4.23) and glibc

(2)         malloc(),        . MALLOC_CHECK_, ( )         ,        , free() -         ( " " ).        , . -        LOC_CHECK_ 0,        ; 1, stderr;         2, (3) ; 3,         stderr, . -         LOC_CHECK_ ,         ,        .

+2

++. ? - . boost Standard. , , .

, , , , , , .

void* malloc(int size) {
    blockheader b; // fill out the structure with e.g. blocksize
    void* mem = allocate_memory(size + sizeof(blockheader));
    memcpy(mem, &b, sizeof(blockheader)); // or memcpy(&b, mem, ...), I can't recall
    return (void*)((char*)mem + sizeof(blockheader)); // return the actual memory
}

free() , . , malloc.

0

-, , , :

#ifdef DEBUG
#define FANCY_FREE(ptr, size) do {memset(ptr, 0xDE, size); free(ptr);} while (0)
#else
#define FANCY_FREE(ptr, size) free(ptr)
#endif

free . , .

0

++, , , UB. , ++ .

0

Source: https://habr.com/ru/post/1776580/


All Articles