<commit_before>/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include "config.h"
#include "alloc_hooks.h"
#include <stdbool.h>

#include "memcached/visibility.h"

#ifdef HAVE_JEMALLOC
/* jemalloc (on Linux at least) assumes you are trying to
 * transparently preload it, and so the exported symbols have no
 * prefix (i.e. malloc,free instead of je_malloc,je_free).
 * To make our code below more explicit we use the 'je_' prefixed
 *  names, so tell JEMALLOC to not demangle these so we link correctly.
 */
#  define JEMALLOC_NO_DEMANGLE 1
#  include <jemalloc/jemalloc.h>
#  if defined(WIN32)
#    error Memory tracking not supported with jemalloc on Windows.
#  elif defined(__APPLE__)
     /* memory tracking implemented using custom malloc zone: */
#    include "darwin_zone.h"
#  else
     /* assume some other *ix-style OS which permits malloc/free symbol interposing. */
#    define INTERPOSE_MALLOC 1
#  endif

#elif defined(HAVE_TCMALLOC)
#include <gperftools/malloc_extension_c.h>
#include <gperftools/malloc_hook_c.h>
#endif

static int (*addNewHook)(void (*hook)(const void *ptr, size_t size));
static int (*removeNewHook)(void (*hook)(const void *ptr, size_t size));
static int (*addDelHook)(void (*hook)(const void *ptr));
static int (*removeDelHook)(void (*hook)(const void *ptr));
static int (*getStatsProp)(const char* property, size_t* value);
static size_t (*getAllocSize)(const void *ptr);
static void (*getDetailedStats)(char *buffer, int nbuffer);
static void (*releaseFreeMemory)(void);
static bool (*enableThreadCache)(bool enable);

static alloc_hooks_type type = none;

#ifdef HAVE_JEMALLOC

/******************************************************************************
 * jemalloc memory tracking support.
 * jemalloc (unlike TCmalloc) has no builtin support for this, so instead we
 * use our own malloc wrapper functions which will check for the presence of
 * registered hooks and call if necessary.
 *
 *****************************************************************************/

/* jemalloc checks for this symbol, and it's contents for the config to use. */
const char* je_malloc_conf =
    /* Use just one arena, instead of the default based on number of CPUs.
       Helps to minimize heap fragmentation. */
    "narenas:1";

static malloc_new_hook_t new_hook = NULL;
static malloc_delete_hook_t delete_hook = NULL;

static inline void invoke_new_hook(void* ptr, size_t size) {
    if (new_hook != NULL) {
        new_hook(ptr, size);
    }
}

static inline void invoke_delete_hook(void* ptr) {
    if (delete_hook != NULL) {
        delete_hook(ptr);
    }
}

#if defined(INTERPOSE_MALLOC)
MEMCACHED_PUBLIC_API void* malloc(size_t size) {
    void* ptr = je_malloc(size);
    invoke_new_hook(ptr, size);
    return ptr;
}

MEMCACHED_PUBLIC_API void* calloc(size_t nmemb, size_t size) {
    void* ptr = je_calloc(nmemb, size);
    invoke_new_hook(ptr, nmemb * size);
    return ptr;
}

MEMCACHED_PUBLIC_API void* realloc(void* ptr, size_t size) {
    invoke_delete_hook(ptr);
    void* result = je_realloc(ptr, size);
    invoke_new_hook(result, size);
    return result;
}

MEMCACHED_PUBLIC_API void free(void* ptr)  {
    invoke_delete_hook(ptr);
    je_free(ptr);
}

#if defined(HAVE_MEMALIGN)
#include <malloc.h>
MEMCACHED_PUBLIC_API void *memalign(size_t alignment, size_t size) {
    void* result = je_memalign(alignment, size);
    invoke_new_hook(result, size);
    return result;
}
#endif

MEMCACHED_PUBLIC_API int posix_memalign(void **memptr, size_t alignment,
                                        size_t size) {
    int result = je_posix_memalign(memptr, alignment, size);
    invoke_new_hook(*memptr, size);
    return result;
}

#endif /* INTERPOSE_MALLOC */

/* Functions to allow users to add/remove new/delete hooks. */
static int jemalloc_add_new_hook(malloc_new_hook_t f)
{
    if (new_hook == NULL) {
        new_hook = f;
        return 1;
    } else {
        return 0;
    }
}

static int jemalloc_remove_new_hook(malloc_new_hook_t f)
{
    if (new_hook == f) {
        new_hook = NULL;
        return 1;
    } else {
        return 0;
    }
}

static int jemalloc_add_delete_hook(malloc_delete_hook_t f)
{
    if (delete_hook == NULL) {
        delete_hook = f;
        return 1;
    } else {
        return 0;
    }
}

static int jemalloc_remove_delete_hook(malloc_delete_hook_t f)
{
    if (delete_hook == f) {
        delete_hook = NULL;
        return 1;
    } else {
        return 0;
    }
}

static int jemalloc_get_stats_prop(const char* property, size_t* value) {
    size_t size = sizeof(*value);
    return je_mallctl(property, value, &size, NULL, 0);
}

static size_t jemalloc_get_alloc_size(const void *ptr) {
    return je_malloc_usable_size(ptr);<commit_msg>Remove compile warning for passing const to non-const<commit_after>/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include "config.h"
#include "alloc_hooks.h"
#include <stdbool.h>

#include "memcached/visibility.h"

#ifdef HAVE_JEMALLOC
/* jemalloc (on Linux at least) assumes you are trying to
 * transparently preload it, and so the exported symbols have no
 * prefix (i.e. malloc,free instead of je_malloc,je_free).
 * To make our code below more explicit we use the 'je_' prefixed
 *  names, so tell JEMALLOC to not demangle these so we link correctly.
 */
#  define JEMALLOC_NO_DEMANGLE 1
#  include <jemalloc/jemalloc.h>
#  if defined(WIN32)
#    error Memory tracking not supported with jemalloc on Windows.
#  elif defined(__APPLE__)
     /* memory tracking implemented using custom malloc zone: */
#    include "darwin_zone.h"
#  else
     /* assume some other *ix-style OS which permits malloc/free symbol interposing. */
#    define INTERPOSE_MALLOC 1
#  endif

#elif defined(HAVE_TCMALLOC)
#include <gperftools/malloc_extension_c.h>
#include <gperftools/malloc_hook_c.h>
#endif

static int (*addNewHook)(void (*hook)(const void *ptr, size_t size));
static int (*removeNewHook)(void (*hook)(const void *ptr, size_t size));
static int (*addDelHook)(void (*hook)(const void *ptr));
static int (*removeDelHook)(void (*hook)(const void *ptr));
static int (*getStatsProp)(const char* property, size_t* value);
static size_t (*getAllocSize)(const void *ptr);
static void (*getDetailedStats)(char *buffer, int nbuffer);
static void (*releaseFreeMemory)(void);
static bool (*enableThreadCache)(bool enable);

static alloc_hooks_type type = none;

#ifdef HAVE_JEMALLOC

/******************************************************************************
 * jemalloc memory tracking support.
 * jemalloc (unlike TCmalloc) has no builtin support for this, so instead we
 * use our own malloc wrapper functions which will check for the presence of
 * registered hooks and call if necessary.
 *
 *****************************************************************************/

/* jemalloc checks for this symbol, and it's contents for the config to use. */
const char* je_malloc_conf =
    /* Use just one arena, instead of the default based on number of CPUs.
       Helps to minimize heap fragmentation. */
    "narenas:1";

static malloc_new_hook_t new_hook = NULL;
static malloc_delete_hook_t delete_hook = NULL;

static inline void invoke_new_hook(void* ptr, size_t size) {
    if (new_hook != NULL) {
        new_hook(ptr, size);
    }
}

static inline void invoke_delete_hook(void* ptr) {
    if (delete_hook != NULL) {
        delete_hook(ptr);
    }
}

#if defined(INTERPOSE_MALLOC)
MEMCACHED_PUBLIC_API void* malloc(size_t size) {
    void* ptr = je_malloc(size);
    invoke_new_hook(ptr, size);
    return ptr;
}

MEMCACHED_PUBLIC_API void* calloc(size_t nmemb, size_t size) {
    void* ptr = je_calloc(nmemb, size);
    invoke_new_hook(ptr, nmemb * size);
    return ptr;
}

MEMCACHED_PUBLIC_API void* realloc(void* ptr, size_t size) {
    invoke_delete_hook(ptr);
    void* result = je_realloc(ptr, size);
    invoke_new_hook(result, size);
    return result;
}

MEMCACHED_PUBLIC_API void free(void* ptr)  {
    invoke_delete_hook(ptr);
    je_free(ptr);
}

#if defined(HAVE_MEMALIGN)
#include <malloc.h>
MEMCACHED_PUBLIC_API void *memalign(size_t alignment, size_t size) {
    void* result = je_memalign(alignment, size);
    invoke_new_hook(result, size);
    return result;
}
#endif

MEMCACHED_PUBLIC_API int posix_memalign(void **memptr, size_t alignment,
                                        size_t size) {
    int result = je_posix_memalign(memptr, alignment, size);
    invoke_new_hook(*memptr, size);
    return result;
}

#endif /* INTERPOSE_MALLOC */

/* Functions to allow users to add/remove new/delete hooks. */
static int jemalloc_add_new_hook(malloc_new_hook_t f)
{
    if (new_hook == NULL) {
        new_hook = f;
        return 1;
    } else {
        return 0;
    }
}

static int jemalloc_remove_new_hook(malloc_new_hook_t f)
{
    if (new_hook == f) {
        new_hook = NULL;
        return 1;
    } else {
        return 0;
    }
}

static int jemalloc_add_delete_hook(malloc_delete_hook_t f)
{
    if (delete_hook == NULL) {
        delete_hook = f;
        return 1;
    } else {
        return 0;
    }
}

static int jemalloc_remove_delete_hook(malloc_delete_hook_t f)
{
    if (delete_hook == f) {
        delete_hook = NULL;
        return 1;
    } else {
        return 0;
    }
}

static int jemalloc_get_stats_prop(const char* property, size_t* value) {
    size_t size = sizeof(*value);
    return je_mallctl(property, value, &size, NULL, 0);
}

static size_t jemalloc_get_alloc_size(const void *ptr) {
    /* je_malloc_usable_size on my linux masks this down to
     * malloc_usable_size causing it to omit a compiler warning.
     * Let's just nuke away the const here, as you may always
     * pass a non-const pointer to a function who accepts a
     * const pointer
     */
    return je_malloc_usable_size((void*)ptr);
{'fraction_non_alphanumeric': 0.1311176410983889, 'fraction_numerical': 0.0032424764413821056, 'mean_word_length': 3.7889374090247454, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4969947', 'n_tokens_mistral': 3289, 'n_tokens_neox': 3202, 'n_words': 945}