<commit_before>/*******************************************************************************
 * thrill/mem/malloc_tracker.cpp
 *
 * Part of Project Thrill.
 *
 * Copyright (C) 2013-2015 <NAME> <<EMAIL>>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <thrill/mem/malloc_tracker.hpp>

#include <atomic>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <dlfcn.h>

#if defined(__clang__) || defined (__GNUC__)
#define ATTRIBUTE_NO_SANITIZE                          \
    __attribute__ ((no_sanitize_address)) /* NOLINT */ \
    __attribute__ ((no_sanitize_thread))  /* NOLINT */
#else
#define ATTRIBUTE_NO_SANITIZE
#endif

namespace thrill {
namespace mem {

//! user-defined options for output malloc()/free() operations to stderr

static const int log_operations = 0; //! <-- set this to 1 for log output
static const size_t log_operations_threshold = 1;

//! to each allocation additional data is added for bookkeeping.
static const size_t padding = 16;    /* bytes (>= 2*sizeof(size_t)) */

//! function pointer to the real procedures, loaded using dlsym()
using malloc_type = void* (*)(size_t);
using free_type = void (*)(void*);
using realloc_type = void* (*)(void*, size_t);

static malloc_type real_malloc = nullptr;
static free_type real_free = nullptr;
static realloc_type real_realloc = nullptr;

//! a sentinel value prefixed to each allocation
static const size_t sentinel = 0xDEADC0DE;

//! a simple memory heap for allocations prior to dlsym loading
#define INIT_HEAP_SIZE 1024 * 1024
static char init_heap[INIT_HEAP_SIZE];
static size_t init_heap_use = 0;
static const int log_operations_init_heap = 0;

//! align allocations to init_heap to this number by rounding up allocations
static const size_t init_alignment = sizeof(size_t);

//! output
#define PPREFIX "malloc_tracker ### "

/*****************************************/
/* run-time memory allocation statistics */
/*****************************************/

static size_t peak = 0;
static size_t curr = 0;
static size_t total = 0;
static size_t total_allocs = 0;
static size_t current_allocs = 0;

//! add allocation to statistics
ATTRIBUTE_NO_SANITIZE
static void inc_count(size_t inc) {
    size_t mycurr = __sync_add_and_fetch(&curr, inc);
    if (mycurr > peak) peak = mycurr;
    total += inc;
    ++total_allocs;
    ++current_allocs;
}

//! decrement allocation to statistics
ATTRIBUTE_NO_SANITIZE
static void dec_count(size_t dec) {
    curr -= dec;
    --current_allocs;
}

//! bypass malloc tracker and access malloc() directly
void * bypass_malloc(size_t size) noexcept {
    return real_malloc(size);
}

//! bypass malloc tracker and access free() directly
void bypass_free(void* ptr) noexcept {
    return real_free(ptr);
}

//! user function to return the currently allocated amount of memory
size_t malloc_tracker_current() {
    return curr;
}

//! user function to return the peak allocation
size_t malloc_tracker_peak() {
    return peak;
}

//! user function to reset the peak allocation to current
void malloc_tracker_reset_peak() {
    peak = curr;
}

//! user function to return total number of allocations
size_t malloc_tracker_total_allocs() {
    return total_allocs;
}

//! user function which prints current and peak allocation to stderr
void malloc_tracker_print_status() {
    fprintf(stderr, PPREFIX "current %lu, peak %lu\n",
            curr, peak);
}

ATTRIBUTE_NO_SANITIZE
static __attribute__ ((constructor)) void init() { // NOLINT
    char* error;

    // try to use AddressSanitizer's malloc first.
    real_malloc = (malloc_type)dlsym(RTLD_DEFAULT, "__interceptor_malloc");
    if (real_malloc)
    {
        real_realloc = (realloc_type)dlsym(RTLD_DEFAULT, "__interceptor_realloc");
        if ((error = dlerror()) != nullptr) {
            fprintf(stderr, PPREFIX "error %s\n", error);
            exit(EXIT_FAILURE);
        }

        real_free = (free_type)dlsym(RTLD_DEFAULT, "__interceptor_free");
        if ((error = dlerror()) != nullptr) {
            fprintf(stderr, PPREFIX "error %s\n", error);
            exit(EXIT_FAILURE);
        }

        fprintf(stderr, PPREFIX "using AddressSanitizer's malloc\n");
        return;
    }

    real_malloc = (malloc_type)dlsym(RTLD_NEXT, "malloc");
    if ((error = dlerror()) != nullptr) {
        fprintf(stderr, PPREFIX "error %s\n", error);
        exit(EXIT_FAILURE);
    }

    real_realloc = (realloc_type)dlsym(RTLD_NEXT, "realloc");
    if ((error = dlerror()) != nullptr) {
        fprintf(stderr, PPREFIX "error %s\n", error);
        exit(EXIT_FAILURE);
    }

    real_free = (free_type)dlsym(RTLD_NEXT, "free");
    if ((error = dlerror()) != nullptr) {
        fprintf(stderr, PPREFIX "error %s\n", error);
        exit(EXIT_FAILURE);
    }
}

ATTRIBUTE_NO_SANITIZE
static __attribute__ ((destructor)) void finish() { // NOLINT
    fprintf(stderr, PPREFIX
            "exiting, total: %lu, peak: %lu, current: %lu, "
            "allocs: %lu, unfreed: %lu\n",
            total, peak, curr,
            total_allocs, current_allocs);
}

} // namespace mem
} // namespace thrill

/****************************************************/
/* exported symbols that overlay the libc functions */
/****************************************************/

using namespace thrill::mem; // NOLINT

ATTRIBUTE_NO_SANITIZE
static void * preinit_malloc(size_t size) noexcept {

    size_t aligned_size = size + (init_alignment - size % init_alignment);

    size_t offset = __sync_fetch_and_add(&init_heap_use, padding + aligned_size);

    if (offset > INIT_HEAP_SIZE) {
        fprintf(stderr, PPREFIX "init heap full !!!\n");
        exit(EXIT_FAILURE);
    }

    char* ret = init_heap + offset;

    //! prepend allocation size and check sentinel
    *reinterpret_cast<size_t*>(ret) = aligned_size;
    *reinterpret_cast<size_t*>(ret + padding - sizeof(size_t)) = sentinel;

    inc_count(aligned_size);

    if (log_operations_init_heap) {
        fprintf(stderr, PPREFIX "malloc(%lu / %lu) = %p   on init heap\n",
                size, aligned_size, ret + padding);
    }

    return ret + padding;
}

ATTRIBUTE_NO_SANITIZE
static void * preinit_realloc(void* ptr, size_t size) noexcept {

    if (log_operations_init_heap) {
        fprintf(stderr, PPREFIX "realloc(%p) = on init heap\n", ptr);
    }

    ptr = static_cast<char*>(ptr) - padding;

    if (*reinterpret_cast<size_t*>(
            static_cast<char*>(ptr) + padding - sizeof(size_t)) != sentinel) {
        fprintf(stderr, PPREFIX
                "realloc(%p) has no sentinel !!! memory corruption?\n",
                ptr);
    }

    size_t oldsize = *reinterpret_cast<size_t*>(ptr);

    if (oldsize >= size) {
        //! keep old area
        return static_cast<char*>(ptr) + padding;
    }
    else {
        //! allocate new area and copy data
        ptr = static_cast<char*>(ptr) + padding;
        void* newptr = malloc(size);
        memcpy(newptr, ptr, oldsize);
        free(ptr);
        return newptr;
    }
}

ATTRIBUTE_NO_SANITIZE
static void preinit_free(void* ptr) noexcept {
    // don't do any real deallocation.

    ptr = static_cast<char*>(ptr) - padding;

    if (*reinterpret_cast<size_t*>(
            static_cast<char*>(ptr) + padding - sizeof(size_t)) != sentinel) {
        fprintf(stderr, PPREFIX
                "free(%p) has no sentinel !!! memory corruption?\n",
                ptr);
    }

    size_t size = *reinterpret_cast<size_t*>(ptr);
    dec_count(size);

    if (log_operations_init_heap) {
        fprintf(stderr, PPREFIX "free(%p) -> %lu   on init heap\n", ptr, size);
    }
}

#define HAVE_MALLOC_USABLE_SIZE 1

#if __APPLE__

#define NOEXCEPT
#define MALLOC_USABLE_SIZE malloc_size
#include <malloc/malloc.h><commit_msg>Removing noexcept, because apparently fprintf can except (?) in g++-5.1.<commit_after>/*******************************************************************************
 * thrill/mem/malloc_tracker.cpp
 *
 * Part of Project Thrill.
 *
 * Copyright (C) 2013-2015 <NAME> <<EMAIL>>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include <thrill/mem/malloc_tracker.hpp>

#include <atomic>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <dlfcn.h>

#if defined(__clang__) || defined (__GNUC__)
#define ATTRIBUTE_NO_SANITIZE                          \
    __attribute__ ((no_sanitize_address)) /* NOLINT */ \
    __attribute__ ((no_sanitize_thread))  /* NOLINT */
#else
#define ATTRIBUTE_NO_SANITIZE
#endif

namespace thrill {
namespace mem {

//! user-defined options for output malloc()/free() operations to stderr

static const int log_operations = 0; //! <-- set this to 1 for log output
static const size_t log_operations_threshold = 1;

//! to each allocation additional data is added for bookkeeping.
static const size_t padding = 16;    /* bytes (>= 2*sizeof(size_t)) */

//! function pointer to the real procedures, loaded using dlsym()
using malloc_type = void* (*)(size_t);
using free_type = void (*)(void*);
using realloc_type = void* (*)(void*, size_t);

static malloc_type real_malloc = nullptr;
static free_type real_free = nullptr;
static realloc_type real_realloc = nullptr;

//! a sentinel value prefixed to each allocation
static const size_t sentinel = 0xDEADC0DE;

//! a simple memory heap for allocations prior to dlsym loading
#define INIT_HEAP_SIZE 1024 * 1024
static char init_heap[INIT_HEAP_SIZE];
static size_t init_heap_use = 0;
static const int log_operations_init_heap = 0;

//! align allocations to init_heap to this number by rounding up allocations
static const size_t init_alignment = sizeof(size_t);

//! output
#define PPREFIX "malloc_tracker ### "

/*****************************************/
/* run-time memory allocation statistics */
/*****************************************/

static size_t peak = 0;
static size_t curr = 0;
static size_t total = 0;
static size_t total_allocs = 0;
static size_t current_allocs = 0;

//! add allocation to statistics
ATTRIBUTE_NO_SANITIZE
static void inc_count(size_t inc) {
    size_t mycurr = __sync_add_and_fetch(&curr, inc);
    if (mycurr > peak) peak = mycurr;
    total += inc;
    ++total_allocs;
    ++current_allocs;
}

//! decrement allocation to statistics
ATTRIBUTE_NO_SANITIZE
static void dec_count(size_t dec) {
    curr -= dec;
    --current_allocs;
}

//! bypass malloc tracker and access malloc() directly
void * bypass_malloc(size_t size) noexcept {
    return real_malloc(size);
}

//! bypass malloc tracker and access free() directly
void bypass_free(void* ptr) noexcept {
    return real_free(ptr);
}

//! user function to return the currently allocated amount of memory
size_t malloc_tracker_current() {
    return curr;
}

//! user function to return the peak allocation
size_t malloc_tracker_peak() {
    return peak;
}

//! user function to reset the peak allocation to current
void malloc_tracker_reset_peak() {
    peak = curr;
}

//! user function to return total number of allocations
size_t malloc_tracker_total_allocs() {
    return total_allocs;
}

//! user function which prints current and peak allocation to stderr
void malloc_tracker_print_status() {
    fprintf(stderr, PPREFIX "current %lu, peak %lu\n",
            curr, peak);
}

ATTRIBUTE_NO_SANITIZE
static __attribute__ ((constructor)) void init() { // NOLINT
    char* error;

    // try to use AddressSanitizer's malloc first.
    real_malloc = (malloc_type)dlsym(RTLD_DEFAULT, "__interceptor_malloc");
    if (real_malloc)
    {
        real_realloc = (realloc_type)dlsym(RTLD_DEFAULT, "__interceptor_realloc");
        if ((error = dlerror()) != nullptr) {
            fprintf(stderr, PPREFIX "error %s\n", error);
            exit(EXIT_FAILURE);
        }

        real_free = (free_type)dlsym(RTLD_DEFAULT, "__interceptor_free");
        if ((error = dlerror()) != nullptr) {
            fprintf(stderr, PPREFIX "error %s\n", error);
            exit(EXIT_FAILURE);
        }

        fprintf(stderr, PPREFIX "using AddressSanitizer's malloc\n");
        return;
    }

    real_malloc = (malloc_type)dlsym(RTLD_NEXT, "malloc");
    if ((error = dlerror()) != nullptr) {
        fprintf(stderr, PPREFIX "error %s\n", error);
        exit(EXIT_FAILURE);
    }

    real_realloc = (realloc_type)dlsym(RTLD_NEXT, "realloc");
    if ((error = dlerror()) != nullptr) {
        fprintf(stderr, PPREFIX "error %s\n", error);
        exit(EXIT_FAILURE);
    }

    real_free = (free_type)dlsym(RTLD_NEXT, "free");
    if ((error = dlerror()) != nullptr) {
        fprintf(stderr, PPREFIX "error %s\n", error);
        exit(EXIT_FAILURE);
    }
}

ATTRIBUTE_NO_SANITIZE
static __attribute__ ((destructor)) void finish() { // NOLINT
    fprintf(stderr, PPREFIX
            "exiting, total: %lu, peak: %lu, current: %lu, "
            "allocs: %lu, unfreed: %lu\n",
            total, peak, curr,
            total_allocs, current_allocs);
}

} // namespace mem
} // namespace thrill

/****************************************************/
/* exported symbols that overlay the libc functions */
/****************************************************/

using namespace thrill::mem; // NOLINT

ATTRIBUTE_NO_SANITIZE
static void * preinit_malloc(size_t size) noexcept {

    size_t aligned_size = size + (init_alignment - size % init_alignment);

    size_t offset = __sync_fetch_and_add(&init_heap_use, padding + aligned_size);

    if (offset > INIT_HEAP_SIZE) {
        fprintf(stderr, PPREFIX "init heap full !!!\n");
        exit(EXIT_FAILURE);
    }

    char* ret = init_heap + offset;

    //! prepend allocation size and check sentinel
    *reinterpret_cast<size_t*>(ret) = aligned_size;
    *reinterpret_cast<size_t*>(ret + padding - sizeof(size_t)) = sentinel;

    inc_count(aligned_size);

    if (log_operations_init_heap) {
        fprintf(stderr, PPREFIX "malloc(%lu / %lu) = %p   on init heap\n",
                size, aligned_size, ret + padding);
    }

    return ret + padding;
}

ATTRIBUTE_NO_SANITIZE
static void * preinit_realloc(void* ptr, size_t size) {

    if (log_operations_init_heap) {
        fprintf(stderr, PPREFIX "realloc(%p) = on init heap\n", ptr);
    }

    ptr = static_cast<char*>(ptr) - padding;

    if (*reinterpret_cast<size_t*>(
            static_cast<char*>(ptr) + padding - sizeof(size_t)) != sentinel) {
        fprintf(stderr, PPREFIX
                "realloc(%p) has no sentinel !!! memory corruption?\n",
                ptr);
    }

    size_t oldsize = *reinterpret_cast<size_t*>(ptr);

    if (oldsize >= size) {
        //! keep old area
        return static_cast<char*>(ptr) + padding;
    }
    else {
        //! allocate new area and copy data
        ptr = static_cast<char*>(ptr) + padding;
        void* newptr = malloc(size);
        memcpy(newptr, ptr, oldsize);
        free(ptr);
        return newptr;
    }
}

ATTRIBUTE_NO_SANITIZE
static void preinit_free(void* ptr) {
    // don't do any real deallocation.

    ptr = static_cast<char*>(ptr) - padding;

    if (*reinterpret_cast<size_t*>(
            static_cast<char*>(ptr) + padding - sizeof(size_t)) != sentinel) {
        fprintf(stderr, PPREFIX
                "free(%p) has no sentinel !!! memory corruption?\n",
                ptr);
    }

    size_t size = *reinterpret_cast<size_t*>(ptr);
    dec_count(size);

    if (log_operations_init_heap) {
        fprintf(stderr, PPREFIX "free(%p) -> %lu   on init heap\n", ptr, size);
    }
}

#define HAVE_MALLOC_USABLE_SIZE 1

#if __APPLE__

#define NOEXCEPT
#define MALLOC_USABLE_SIZE malloc_size
#include <malloc/malloc.h>
{'fraction_non_alphanumeric': 0.15583676051882317, 'fraction_numerical': 0.0041758937045238845, 'mean_word_length': 3.4436322743885297, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '336460', 'n_tokens_mistral': 5148, 'n_tokens_neox': 4935, 'n_words': 1325}