| /* |
| * Copyright (c) 2010 The WebM project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| |
| /* |
| vpx_mem_tracker.c |
| |
| jwz 2003-09-30: |
| Stores a list of addreses, their size, and file and line they came from. |
| All exposed lib functions are prefaced by vpx_ and allow the global list |
| to be thread safe. |
| Current supported platforms are: |
| Linux, Win32, win_ce and vx_works |
| Further support can be added by defining the platform specific mutex |
| in the memory_tracker struct as well as calls to create/destroy/lock/unlock |
| the mutex in vpx_memory_tracker_init/Destroy and memory_tracker_lock_mutex/unlock_mutex |
| */ |
| #include "vpx_ports/config.h" |
| |
| #if defined(__uClinux__) |
| # include <lddk.h> |
| #endif |
| |
| #if HAVE_PTHREAD_H |
| # include <pthread.h> |
| #elif defined(WIN32) || defined(_WIN32_WCE) |
| # define WIN32_LEAN_AND_MEAN |
| # include <windows.h> |
| # include <winbase.h> |
| #elif defined(VXWORKS) |
| # include <sem_lib.h> |
| #elif defined(NDS_NITRO) |
| # include <nitro.h> |
| # include <nitro/os.h> |
| #endif |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> //VXWORKS doesn't have a malloc/memory.h file, |
| //this should pull in malloc,free,etc. |
| #include <stdarg.h> |
| |
| #include "include/vpx_mem_tracker.h" |
| |
| #undef vpx_malloc //undefine any vpx_mem macros that may affect calls to |
| #undef vpx_free //memory functions in this file |
| #undef vpx_memcpy |
| #undef vpx_memset |
| |
| |
| #ifndef USE_GLOBAL_FUNCTION_POINTERS |
| # define USE_GLOBAL_FUNCTION_POINTERS 0 //use function pointers instead of compiled functions. |
| #endif |
| |
| #if USE_GLOBAL_FUNCTION_POINTERS |
| static mem_track_malloc_func g_malloc = malloc; |
| static mem_track_calloc_func g_calloc = calloc; |
| static mem_track_realloc_func g_realloc = realloc; |
| static mem_track_free_func g_free = free; |
| static mem_track_memcpy_func g_memcpy = memcpy; |
| static mem_track_memset_func g_memset = memset; |
| static mem_track_memmove_func g_memmove = memmove; |
| # define MEM_TRACK_MALLOC g_malloc |
| # define MEM_TRACK_FREE g_free |
| # define MEM_TRACK_MEMCPY g_memcpy |
| # define MEM_TRACK_MEMSET g_memset |
| #else |
| # define MEM_TRACK_MALLOC vpx_malloc |
| # define MEM_TRACK_FREE vpx_free |
| # define MEM_TRACK_MEMCPY vpx_memcpy |
| # define MEM_TRACK_MEMSET vpx_memset |
| #endif // USE_GLOBAL_FUNCTION_POINTERS |
| |
| /* prototypes for internal library functions */ |
| static void memtrack_log(const char *fmt, ...); |
| static void memory_tracker_dump(); |
| static void memory_tracker_check_integrity(char *file, unsigned int line); |
| static void memory_tracker_add(size_t addr, unsigned int size, |
| char *file, unsigned int line, |
| int padded); |
| static int memory_tracker_remove(size_t addr); |
| static struct mem_block *memory_tracker_find(size_t addr); |
| |
| #if defined(NO_MUTEX) |
| # define memory_tracker_lock_mutex() (!g_b_mem_tracker_inited) |
| # define memory_tracker_unlock_mutex() |
| #else |
| static int memory_tracker_lock_mutex(); |
| static int memory_tracker_unlock_mutex(); |
| #endif |
| |
| #ifndef VPX_NO_GLOBALS |
| struct memory_tracker |
| { |
| struct mem_block *head, |
| * tail; |
| int len, |
| totalsize; |
| unsigned int current_allocated, |
| max_allocated; |
| |
| #if HAVE_PTHREAD_H |
| pthread_mutex_t mutex; |
| #elif defined(WIN32) || defined(_WIN32_WCE) |
| HANDLE mutex; |
| #elif defined(VXWORKS) |
| SEM_ID mutex; |
| #elif defined(NDS_NITRO) |
| OSMutex mutex; |
| #elif defined(NO_MUTEX) |
| #else |
| #error "No mutex type defined for this platform!" |
| #endif |
| |
| int padding_size, |
| pad_value; |
| }; |
| |
| static struct memory_tracker memtrack; //our global memory allocation list |
| static int g_b_mem_tracker_inited = 0; //indicates whether the global list has |
| //been initialized (1:yes/0:no) |
| static struct |
| { |
| FILE *file; |
| int type; |
| void (*func)(void *userdata, const char *fmt, va_list args); |
| void *userdata; |
| } g_logging = {NULL, 0, NULL, NULL}; |
| #else |
| # include "vpx_global_handling.h" |
| #define g_b_mem_tracker_inited vpxglobalm(vpxmem,g_b_mem_tracker_inited) |
| #define g_logging vpxglobalm(vpxmem,g_logging) |
| #define memtrack vpxglobalm(vpxmem,memtrack) |
| #endif // #ifndef VPX_NO_GLOBALS |
| |
| extern void *vpx_malloc(size_t size); |
| extern void vpx_free(void *memblk); |
| extern void *vpx_memcpy(void *dest, const void *src, size_t length); |
| extern void *vpx_memset(void *dest, int val, size_t length); |
| |
| /* |
| * |
| * Exposed library functions |
| * |
| */ |
| |
| /* |
| vpx_memory_tracker_init(int padding_size, int pad_value) |
| padding_size - the size of the padding before and after each mem addr. |
| Values > 0 indicate that integrity checks can be performed |
| by inspecting these areas. |
| pad_value - the initial value within the padding area before and after |
| each mem addr. |
| |
| Initializes global memory tracker structure |
| Allocates the head of the list |
| */ |
| int vpx_memory_tracker_init(int padding_size, int pad_value) |
| { |
| if (!g_b_mem_tracker_inited) |
| { |
| if ((memtrack.head = (struct mem_block *) |
| MEM_TRACK_MALLOC(sizeof(struct mem_block)))) |
| { |
| int ret; |
| |
| MEM_TRACK_MEMSET(memtrack.head, 0, sizeof(struct mem_block)); |
| |
| memtrack.tail = memtrack.head; |
| |
| memtrack.current_allocated = 0; |
| memtrack.max_allocated = 0; |
| |
| memtrack.padding_size = padding_size; |
| memtrack.pad_value = pad_value; |
| |
| #if HAVE_PTHREAD_H |
| ret = pthread_mutex_init(&memtrack.mutex, |
| NULL); /*mutex attributes (NULL=default)*/ |
| #elif defined(WIN32) || defined(_WIN32_WCE) |
| memtrack.mutex = CreateMutex(NULL, /*security attributes*/ |
| FALSE, /*we don't want initial ownership*/ |
| NULL); /*mutex name*/ |
| ret = !memtrack.mutex; |
| #elif defined(VXWORKS) |
| memtrack.mutex = sem_bcreate(SEM_Q_FIFO, /*SEM_Q_FIFO non-priority based mutex*/ |
| SEM_FULL); /*SEM_FULL initial state is unlocked*/ |
| ret = !memtrack.mutex; |
| #elif defined(NDS_NITRO) |
| os_init_mutex(&memtrack.mutex); |
| ret = 0; |
| #elif defined(NO_MUTEX) |
| ret = 0; |
| #endif |
| |
| if (ret) |
| { |
| memtrack_log("vpx_memory_tracker_init: Error creating mutex!\n"); |
| |
| MEM_TRACK_FREE(memtrack.head); |
| memtrack.head = NULL; |
| } |
| else |
| { |
| memtrack_log("Memory Tracker init'd, v."vpx_mem_tracker_version" pad_size:%d pad_val:0x%x %d\n" |
| , padding_size |
| , pad_value |
| , pad_value); |
| g_b_mem_tracker_inited = 1; |
| } |
| } |
| } |
| |
| return g_b_mem_tracker_inited; |
| } |
| |
| /* |
| vpx_memory_tracker_destroy() |
| If our global struct was initialized zeros out all its members, |
| frees memory and destroys it's mutex |
| */ |
| void vpx_memory_tracker_destroy() |
| { |
| if (!memory_tracker_lock_mutex()) |
| { |
| struct mem_block *p = memtrack.head, |
| * p2 = memtrack.head; |
| |
| memory_tracker_dump(); |
| |
| while (p) |
| { |
| p2 = p; |
| p = p->next; |
| |
| MEM_TRACK_FREE(p2); |
| } |
| |
| memtrack.head = NULL; |
| memtrack.tail = NULL; |
| memtrack.len = 0; |
| memtrack.current_allocated = 0; |
| memtrack.max_allocated = 0; |
| |
| if (!g_logging.type && g_logging.file && g_logging.file != stderr) |
| { |
| #if !defined(NDS_NITRO) |
| fclose(g_logging.file); |
| #endif |
| g_logging.file = NULL; |
| } |
| |
| memory_tracker_unlock_mutex(); |
| |
| g_b_mem_tracker_inited = 0; |
| } |
| } |
| |
| /* |
| vpx_memory_tracker_add(size_t addr, unsigned int size, |
| char * file, unsigned int line) |
| addr - memory address to be added to list |
| size - size of addr |
| file - the file addr was referenced from |
| line - the line in file addr was referenced from |
| Adds memory address addr, it's size, file and line it came from |
| to the global list via the thread safe internal library function |
| */ |
| void vpx_memory_tracker_add(size_t addr, unsigned int size, |
| char *file, unsigned int line, |
| int padded) |
| { |
| memory_tracker_add(addr, size, file, line, padded); |
| } |
| |
| /* |
| vpx_memory_tracker_remove(size_t addr) |
| addr - memory address to be removed from list |
| Removes addr from the global list via the thread safe |
| internal remove function |
| Return: |
| Same as described for memory_tracker_remove |
| */ |
| int vpx_memory_tracker_remove(size_t addr) |
| { |
| return memory_tracker_remove(addr); |
| } |
| |
| /* |
| vpx_memory_tracker_find(size_t addr) |
| addr - address to be found in list |
| Return: |
| If found, pointer to the memory block that matches addr |
| NULL otherwise |
| */ |
| struct mem_block *vpx_memory_tracker_find(size_t addr) |
| { |
| struct mem_block *p = NULL; |
| |
| if (!memory_tracker_lock_mutex()) |
| { |
| p = memory_tracker_find(addr); |
| memory_tracker_unlock_mutex(); |
| } |
| |
| return p; |
| } |
| |
| /* |
| vpx_memory_tracker_dump() |
| Locks the memory tracker's mutex and calls the internal |
| library function to dump the current contents of the |
| global memory allocation list |
| */ |
| void vpx_memory_tracker_dump() |
| { |
| if (!memory_tracker_lock_mutex()) |
| { |
| memory_tracker_dump(); |
| memory_tracker_unlock_mutex(); |
| } |
| } |
| |
| /* |
| vpx_memory_tracker_check_integrity(char* file, unsigned int line) |
| file - The file name where the check was placed |
| line - The line in file where the check was placed |
| Locks the memory tracker's mutex and calls the internal |
| integrity check function to inspect every address in the global |
| memory allocation list |
| */ |
| void vpx_memory_tracker_check_integrity(char *file, unsigned int line) |
| { |
| if (!memory_tracker_lock_mutex()) |
| { |
| memory_tracker_check_integrity(file, line); |
| memory_tracker_unlock_mutex(); |
| } |
| } |
| |
| /* |
| vpx_memory_tracker_set_log_type |
| Sets the logging type for the memory tracker. Based on the value it will |
| direct its output to the appropriate place. |
| Return: |
| 0: on success |
| -1: if the logging type could not be set, because the value was invalid |
| or because a file could not be opened |
| */ |
| int vpx_memory_tracker_set_log_type(int type, char *option) |
| { |
| int ret = -1; |
| |
| switch (type) |
| { |
| case 0: |
| g_logging.type = 0; |
| |
| if (!option) |
| { |
| g_logging.file = stderr; |
| ret = 0; |
| } |
| |
| #if !defined(NDS_NITRO) |
| else |
| { |
| if ((g_logging.file = fopen((char *)option, "w"))) |
| ret = 0; |
| } |
| |
| #endif |
| break; |
| #if defined(WIN32) && !defined(_WIN32_WCE) |
| case 1: |
| g_logging.type = type; |
| ret = 0; |
| break; |
| #endif |
| default: |
| break; |
| } |
| |
| //output the version to the new logging destination |
| if (!ret) |
| memtrack_log("Memory Tracker logging initialized, " |
| "Memory Tracker v."vpx_mem_tracker_version"\n"); |
| |
| return ret; |
| } |
| |
| /* |
| vpx_memory_tracker_set_log_func |
| Sets a logging function to be used by the memory tracker. |
| Return: |
| 0: on success |
| -1: if the logging type could not be set because logfunc was NULL |
| */ |
| int vpx_memory_tracker_set_log_func(void *userdata, |
| void(*logfunc)(void *userdata, |
| const char *fmt, va_list args)) |
| { |
| int ret = -1; |
| |
| if (logfunc) |
| { |
| g_logging.type = -1; |
| g_logging.userdata = userdata; |
| g_logging.func = logfunc; |
| ret = 0; |
| } |
| |
| //output the version to the new logging destination |
| if (!ret) |
| memtrack_log("Memory Tracker logging initialized, " |
| "Memory Tracker v."vpx_mem_tracker_version"\n"); |
| |
| return ret; |
| } |
| |
| /* |
| * |
| * END - Exposed library functions |
| * |
| */ |
| |
| |
| /* |
| * |
| * Internal library functions |
| * |
| */ |
| |
| static void memtrack_log(const char *fmt, ...) |
| { |
| va_list list; |
| |
| va_start(list, fmt); |
| |
| switch (g_logging.type) |
| { |
| case -1: |
| |
| if (g_logging.func) |
| g_logging.func(g_logging.userdata, fmt, list); |
| |
| break; |
| case 0: |
| |
| if (g_logging.file) |
| { |
| vfprintf(g_logging.file, fmt, list); |
| fflush(g_logging.file); |
| } |
| |
| break; |
| #if defined(WIN32) && !defined(_WIN32_WCE) |
| case 1: |
| { |
| char temp[1024]; |
| _vsnprintf(temp, sizeof(temp) / sizeof(char) - 1, fmt, list); |
| OutputDebugString(temp); |
| } |
| break; |
| #endif |
| default: |
| break; |
| } |
| |
| va_end(list); |
| } |
| |
| /* |
| memory_tracker_dump() |
| Dumps the current contents of the global memory allocation list |
| */ |
| static void memory_tracker_dump() |
| { |
| int i = 0; |
| struct mem_block *p = (memtrack.head ? memtrack.head->next : NULL); |
| |
| memtrack_log("\n_currently Allocated= %d; Max allocated= %d\n", |
| memtrack.current_allocated, memtrack.max_allocated); |
| |
| while (p) |
| { |
| #if defined(WIN32) && !defined(_WIN32_WCE) |
| |
| /*when using outputdebugstring, output filenames so they |
| can be clicked to be opened in visual studio*/ |
| if (g_logging.type == 1) |
| memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file:\n" |
| " %s(%d):\n", i, |
| p->addr, i, p->size, |
| p->file, p->line); |
| else |
| #endif |
| memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file: %s, line: %d\n", i, |
| p->addr, i, p->size, |
| p->file, p->line); |
| |
| #ifdef NDS_NITRO |
| |
| if (!(i % 20)) os_sleep(500); |
| |
| #endif |
| |
| p = p->next; |
| ++i; |
| } |
| |
| memtrack_log("\n"); |
| } |
| |
| /* |
| memory_tracker_check_integrity(char* file, unsigned int file) |
| file - the file name where the check was placed |
| line - the line in file where the check was placed |
| If a padding_size was supplied to vpx_memory_tracker_init() |
| this function will check ea. addr in the list verifying that |
| addr-padding_size and addr+padding_size is filled with pad_value |
| */ |
| static void memory_tracker_check_integrity(char *file, unsigned int line) |
| { |
| if (memtrack.padding_size) |
| { |
| int i, |
| index = 0; |
| unsigned char *p_show_me, |
| * p_show_me2; |
| unsigned int tempme = memtrack.pad_value, |
| dead1, |
| dead2; |
| unsigned char *x_bounds; |
| struct mem_block *p = memtrack.head->next; |
| |
| while (p) |
| { |
| //x_bounds = (unsigned char*)p->addr; |
| //back up VPX_BYTE_ALIGNMENT |
| //x_bounds -= memtrack.padding_size; |
| |
| if (p->padded) // can the bounds be checked? |
| { |
| /*yes, move to the address that was actually allocated |
| by the vpx_* calls*/ |
| x_bounds = (unsigned char *)(((size_t *)p->addr)[-1]); |
| |
| for (i = 0; i < memtrack.padding_size; i += sizeof(unsigned int)) |
| { |
| p_show_me = (x_bounds + i); |
| p_show_me2 = (unsigned char *)(p->addr + p->size + i); |
| |
| MEM_TRACK_MEMCPY(&dead1, p_show_me, sizeof(unsigned int)); |
| MEM_TRACK_MEMCPY(&dead2, p_show_me2, sizeof(unsigned int)); |
| |
| if ((dead1 != tempme) || (dead2 != tempme)) |
| { |
| memtrack_log("\n[vpx_mem integrity check failed]:\n" |
| " index[%d,%d] {%s:%d} addr=0x%x, size=%d," |
| " file: %s, line: %d c0:0x%x c1:0x%x\n", |
| index, i, file, line, p->addr, p->size, p->file, |
| p->line, dead1, dead2); |
| } |
| } |
| } |
| |
| ++index; |
| p = p->next; |
| } |
| } |
| } |
| |
| /* |
| memory_tracker_add(size_t addr, unsigned int size, |
| char * file, unsigned int line) |
| Adds an address (addr), it's size, file and line number to our list. |
| Adjusts the total bytes allocated and max bytes allocated if necessary. |
| If memory cannot be allocated the list will be destroyed. |
| */ |
| void memory_tracker_add(size_t addr, unsigned int size, |
| char *file, unsigned int line, |
| int padded) |
| { |
| if (!memory_tracker_lock_mutex()) |
| { |
| struct mem_block *p; |
| |
| p = MEM_TRACK_MALLOC(sizeof(struct mem_block)); |
| |
| if (p) |
| { |
| p->prev = memtrack.tail; |
| p->prev->next = p; |
| p->addr = addr; |
| p->size = size; |
| p->line = line; |
| p->file = file; |
| p->padded = padded; |
| p->next = NULL; |
| |
| memtrack.tail = p; |
| |
| memtrack.current_allocated += size; |
| |
| if (memtrack.current_allocated > memtrack.max_allocated) |
| memtrack.max_allocated = memtrack.current_allocated; |
| |
| //memtrack_log("memory_tracker_add: added addr=0x%.8x\n", addr); |
| |
| memory_tracker_unlock_mutex(); |
| } |
| else |
| { |
| memtrack_log("memory_tracker_add: error allocating memory!\n"); |
| memory_tracker_unlock_mutex(); |
| vpx_memory_tracker_destroy(); |
| } |
| } |
| } |
| |
| /* |
| memory_tracker_remove(size_t addr) |
| Removes an address and its corresponding size (if they exist) |
| from the memory tracker list and adjusts the current number |
| of bytes allocated. |
| Return: |
| 0: on success |
| -1: if the mutex could not be locked |
| -2: if the addr was not found in the list |
| */ |
| int memory_tracker_remove(size_t addr) |
| { |
| int ret = -1; |
| |
| if (!memory_tracker_lock_mutex()) |
| { |
| struct mem_block *p; |
| |
| if ((p = memory_tracker_find(addr))) |
| { |
| memtrack.current_allocated -= p->size; |
| |
| p->prev->next = p->next; |
| |
| if (p->next) |
| p->next->prev = p->prev; |
| else |
| memtrack.tail = p->prev; |
| |
| ret = 0; |
| MEM_TRACK_FREE(p); |
| } |
| else |
| { |
| if (addr) |
| memtrack_log("memory_tracker_remove(): addr not found in list," |
| " 0x%.8x\n", addr); |
| |
| ret = -2; |
| } |
| |
| memory_tracker_unlock_mutex(); |
| } |
| |
| return ret; |
| } |
| |
| /* |
| memory_tracker_find(size_t addr) |
| Finds an address in our addrs list |
| NOTE: the mutex MUST be locked in the other internal |
| functions before calling this one. This avoids |
| the need for repeated locking and unlocking as in Remove |
| Returns: pointer to the mem block if found, NULL otherwise |
| */ |
| static struct mem_block *memory_tracker_find(size_t addr) |
| { |
| struct mem_block *p = NULL; |
| |
| if (memtrack.head) |
| { |
| p = memtrack.head->next; |
| |
| while (p && (p->addr != addr)) |
| p = p->next; |
| } |
| |
| return p; |
| } |
| |
| |
| #if !defined(NO_MUTEX) |
| /* |
| memory_tracker_lock_mutex() |
| Locks the memory tracker mutex with a platform specific call |
| Returns: |
| 0: Success |
| <0: Failure, either the mutex was not initialized |
| or the call to lock the mutex failed |
| */ |
| static int memory_tracker_lock_mutex() |
| { |
| int ret = -1; |
| |
| if (g_b_mem_tracker_inited) |
| { |
| |
| #if HAVE_PTHREAD_H |
| ret = pthread_mutex_lock(&memtrack.mutex); |
| #elif defined(WIN32) || defined(_WIN32_WCE) |
| ret = WaitForSingleObject(memtrack.mutex, INFINITE); |
| #elif defined(VXWORKS) |
| ret = sem_take(memtrack.mutex, WAIT_FOREVER); |
| #elif defined(NDS_NITRO) |
| os_lock_mutex(&memtrack.mutex); |
| ret = 0; |
| #endif |
| |
| if (ret) |
| { |
| memtrack_log("memory_tracker_lock_mutex: mutex lock failed\n"); |
| } |
| } |
| |
| return ret; |
| } |
| |
| /* |
| memory_tracker_unlock_mutex() |
| Unlocks the memory tracker mutex with a platform specific call |
| Returns: |
| 0: Success |
| <0: Failure, either the mutex was not initialized |
| or the call to unlock the mutex failed |
| */ |
| static int memory_tracker_unlock_mutex() |
| { |
| int ret = -1; |
| |
| if (g_b_mem_tracker_inited) |
| { |
| |
| #if HAVE_PTHREAD_H |
| ret = pthread_mutex_unlock(&memtrack.mutex); |
| #elif defined(WIN32) || defined(_WIN32_WCE) |
| ret = !ReleaseMutex(memtrack.mutex); |
| #elif defined(VXWORKS) |
| ret = sem_give(memtrack.mutex); |
| #elif defined(NDS_NITRO) |
| os_unlock_mutex(&memtrack.mutex); |
| ret = 0; |
| #endif |
| |
| if (ret) |
| { |
| memtrack_log("memory_tracker_unlock_mutex: mutex unlock failed\n"); |
| } |
| } |
| |
| return ret; |
| } |
| #endif |
| |
| /* |
| vpx_memory_tracker_set_functions |
| |
| Sets the function pointers for the standard library functions. |
| |
| Return: |
| 0: on success |
| -1: if the use global function pointers is not set. |
| */ |
| int vpx_memory_tracker_set_functions(mem_track_malloc_func g_malloc_l |
| , mem_track_calloc_func g_calloc_l |
| , mem_track_realloc_func g_realloc_l |
| , mem_track_free_func g_free_l |
| , mem_track_memcpy_func g_memcpy_l |
| , mem_track_memset_func g_memset_l |
| , mem_track_memmove_func g_memmove_l) |
| { |
| #if USE_GLOBAL_FUNCTION_POINTERS |
| |
| if (g_malloc_l) |
| g_malloc = g_malloc_l; |
| |
| if (g_calloc_l) |
| g_calloc = g_calloc_l; |
| |
| if (g_realloc_l) |
| g_realloc = g_realloc_l; |
| |
| if (g_free_l) |
| g_free = g_free_l; |
| |
| if (g_memcpy_l) |
| g_memcpy = g_memcpy_l; |
| |
| if (g_memset_l) |
| g_memset = g_memset_l; |
| |
| if (g_memmove_l) |
| g_memmove = g_memmove_l; |
| |
| return 0; |
| #else |
| (void)g_malloc_l; |
| (void)g_calloc_l; |
| (void)g_realloc_l; |
| (void)g_free_l; |
| (void)g_memcpy_l; |
| (void)g_memset_l; |
| (void)g_memmove_l; |
| return -1; |
| #endif |
| } |