1 /*
2  *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 
12 /*
13   vpx_mem_tracker.c
14 
15   jwz 2003-09-30:
16    Stores a list of addreses, their size, and file and line they came from.
17    All exposed lib functions are prefaced by vpx_ and allow the global list
18    to be thread safe.
19    Current supported platforms are:
20     Linux, Win32, win_ce and vx_works
21    Further support can be added by defining the platform specific mutex
22    in the memory_tracker struct as well as calls to create/destroy/lock/unlock
23    the mutex in vpx_memory_tracker_init/Destroy and memory_tracker_lock_mutex/unlock_mutex
24 */
25 #include "./vpx_config.h"
26 
27 #if defined(__uClinux__)
28 # include <lddk.h>
29 #endif
30 
31 #if HAVE_PTHREAD_H
32 # include <pthread.h>
33 #elif defined(WIN32) || defined(_WIN32_WCE)
34 # define WIN32_LEAN_AND_MEAN
35 # include <windows.h>
36 # include <winbase.h>
37 #elif defined(VXWORKS)
38 # include <sem_lib.h>
39 #endif
40 
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h> // VXWORKS doesn't have a malloc/memory.h file,
44 // this should pull in malloc,free,etc.
45 #include <stdarg.h>
46 
47 #include "include/vpx_mem_tracker.h"
48 
49 #undef vpx_malloc   // undefine any vpx_mem macros that may affect calls to
50 #undef vpx_free     // memory functions in this file
51 #undef vpx_memcpy
52 #undef vpx_memset
53 
54 
55 #ifndef USE_GLOBAL_FUNCTION_POINTERS
56 # define USE_GLOBAL_FUNCTION_POINTERS   0  // use function pointers instead of compiled functions.
57 #endif
58 
59 #if USE_GLOBAL_FUNCTION_POINTERS
60 static mem_track_malloc_func g_malloc   = malloc;
61 static mem_track_calloc_func g_calloc   = calloc;
62 static mem_track_realloc_func g_realloc = realloc;
63 static mem_track_free_func g_free       = free;
64 static mem_track_memcpy_func g_memcpy   = memcpy;
65 static mem_track_memset_func g_memset   = memset;
66 static mem_track_memmove_func g_memmove = memmove;
67 # define MEM_TRACK_MALLOC g_malloc
68 # define MEM_TRACK_FREE   g_free
69 # define MEM_TRACK_MEMCPY g_memcpy
70 # define MEM_TRACK_MEMSET g_memset
71 #else
72 # define MEM_TRACK_MALLOC vpx_malloc
73 # define MEM_TRACK_FREE   vpx_free
74 # define MEM_TRACK_MEMCPY vpx_memcpy
75 # define MEM_TRACK_MEMSET vpx_memset
76 #endif // USE_GLOBAL_FUNCTION_POINTERS
77 
78 /* prototypes for internal library functions */
79 static void memtrack_log(const char *fmt, ...);
80 static void memory_tracker_dump();
81 static void memory_tracker_check_integrity(char *file, unsigned int line);
82 static void memory_tracker_add(size_t addr, unsigned int size,
83                                char *file, unsigned int line,
84                                int padded);
85 static int memory_tracker_remove(size_t addr);
86 static struct mem_block *memory_tracker_find(size_t addr);
87 
88 #if defined(NO_MUTEX)
89 # define memory_tracker_lock_mutex() (!g_b_mem_tracker_inited)
90 # define memory_tracker_unlock_mutex()
91 #else
92 static int memory_tracker_lock_mutex();
93 static int memory_tracker_unlock_mutex();
94 #endif
95 
96 #ifndef VPX_NO_GLOBALS
97 struct memory_tracker {
98   struct mem_block *head,
99       * tail;
100   int len,
101       totalsize;
102   unsigned int current_allocated,
103            max_allocated;
104 
105 #if HAVE_PTHREAD_H
106   pthread_mutex_t mutex;
107 #elif defined(WIN32) || defined(_WIN32_WCE)
108   HANDLE mutex;
109 #elif defined(VXWORKS)
110   SEM_ID mutex;
111 #elif defined(NO_MUTEX)
112 #else
113 #error "No mutex type defined for this platform!"
114 #endif
115 
116   int padding_size,
117       pad_value;
118 };
119 
120 static struct memory_tracker memtrack;   // our global memory allocation list
121 static int g_b_mem_tracker_inited = 0;     // indicates whether the global list has
122 // been initialized (1:yes/0:no)
123 static struct {
124   FILE *file;
125   int type;
126   void (*func)(void *userdata, const char *fmt, va_list args);
127   void *userdata;
128 } g_logging = {NULL, 0, NULL, NULL};
129 #else
130 # include "vpx_global_handling.h"
131 #define g_b_mem_tracker_inited vpxglobalm(vpxmem,g_b_mem_tracker_inited)
132 #define g_logging vpxglobalm(vpxmem,g_logging)
133 #define memtrack vpxglobalm(vpxmem,memtrack)
134 #endif // #ifndef VPX_NO_GLOBALS
135 
136 extern void *vpx_malloc(size_t size);
137 extern void vpx_free(void *memblk);
138 extern void *vpx_memcpy(void *dest, const void *src, size_t length);
139 extern void *vpx_memset(void *dest, int val, size_t length);
140 
141 /*
142  *
143  * Exposed library functions
144  *
145 */
146 
147 /*
148     vpx_memory_tracker_init(int padding_size, int pad_value)
149       padding_size - the size of the padding before and after each mem addr.
150                      Values > 0 indicate that integrity checks can be performed
151                      by inspecting these areas.
152       pad_value - the initial value within the padding area before and after
153                   each mem addr.
154 
155     Initializes global memory tracker structure
156     Allocates the head of the list
157 */
vpx_memory_tracker_init(int padding_size,int pad_value)158 int vpx_memory_tracker_init(int padding_size, int pad_value) {
159   if (!g_b_mem_tracker_inited) {
160     if ((memtrack.head = (struct mem_block *)
161                          MEM_TRACK_MALLOC(sizeof(struct mem_block)))) {
162       int ret;
163 
164       MEM_TRACK_MEMSET(memtrack.head, 0, sizeof(struct mem_block));
165 
166       memtrack.tail = memtrack.head;
167 
168       memtrack.current_allocated = 0;
169       memtrack.max_allocated     = 0;
170 
171       memtrack.padding_size = padding_size;
172       memtrack.pad_value    = pad_value;
173 
174 #if HAVE_PTHREAD_H
175       ret = pthread_mutex_init(&memtrack.mutex,
176                                NULL);            /*mutex attributes (NULL=default)*/
177 #elif defined(WIN32) || defined(_WIN32_WCE)
178       memtrack.mutex = CreateMutex(NULL,   /*security attributes*/
179                                    FALSE,  /*we don't want initial ownership*/
180                                    NULL);  /*mutex name*/
181       ret = !memtrack.mutex;
182 #elif defined(VXWORKS)
183       memtrack.mutex = sem_bcreate(SEM_Q_FIFO, /*SEM_Q_FIFO non-priority based mutex*/
184                                    SEM_FULL);  /*SEM_FULL initial state is unlocked*/
185       ret = !memtrack.mutex;
186 #elif defined(NO_MUTEX)
187       ret = 0;
188 #endif
189 
190       if (ret) {
191         memtrack_log("vpx_memory_tracker_init: Error creating mutex!\n");
192 
193         MEM_TRACK_FREE(memtrack.head);
194         memtrack.head = NULL;
195       } else {
196         memtrack_log("Memory Tracker init'd, v."vpx_mem_tracker_version" pad_size:%d pad_val:0x%x %d\n"
197 , padding_size
198 , pad_value
199 , pad_value);
200         g_b_mem_tracker_inited = 1;
201       }
202     }
203   }
204 
205   return g_b_mem_tracker_inited;
206 }
207 
208 /*
209     vpx_memory_tracker_destroy()
210     If our global struct was initialized zeros out all its members,
211     frees memory and destroys it's mutex
212 */
vpx_memory_tracker_destroy()213 void vpx_memory_tracker_destroy() {
214   if (!memory_tracker_lock_mutex()) {
215     struct mem_block *p  = memtrack.head,
216                           * p2 = memtrack.head;
217 
218     memory_tracker_dump();
219 
220     while (p) {
221       p2 = p;
222       p  = p->next;
223 
224       MEM_TRACK_FREE(p2);
225     }
226 
227     memtrack.head              = NULL;
228     memtrack.tail              = NULL;
229     memtrack.len               = 0;
230     memtrack.current_allocated = 0;
231     memtrack.max_allocated     = 0;
232 
233     if (!g_logging.type && g_logging.file && g_logging.file != stderr) {
234       fclose(g_logging.file);
235       g_logging.file = NULL;
236     }
237 
238     memory_tracker_unlock_mutex();
239 
240     g_b_mem_tracker_inited = 0;
241   }
242 }
243 
244 /*
245     vpx_memory_tracker_add(size_t addr, unsigned int size,
246                          char * file, unsigned int line)
247       addr - memory address to be added to list
248       size - size of addr
249       file - the file addr was referenced from
250       line - the line in file addr was referenced from
251     Adds memory address addr, it's size, file and line it came from
252     to the global list via the thread safe internal library function
253 */
vpx_memory_tracker_add(size_t addr,unsigned int size,char * file,unsigned int line,int padded)254 void vpx_memory_tracker_add(size_t addr, unsigned int size,
255                             char *file, unsigned int line,
256                             int padded) {
257   memory_tracker_add(addr, size, file, line, padded);
258 }
259 
260 /*
261     vpx_memory_tracker_remove(size_t addr)
262       addr - memory address to be removed from list
263     Removes addr from the global list via the thread safe
264     internal remove function
265     Return:
266       Same as described for memory_tracker_remove
267 */
vpx_memory_tracker_remove(size_t addr)268 int vpx_memory_tracker_remove(size_t addr) {
269   return memory_tracker_remove(addr);
270 }
271 
272 /*
273     vpx_memory_tracker_find(size_t addr)
274       addr - address to be found in list
275     Return:
276         If found, pointer to the memory block that matches addr
277         NULL otherwise
278 */
vpx_memory_tracker_find(size_t addr)279 struct mem_block *vpx_memory_tracker_find(size_t addr) {
280   struct mem_block *p = NULL;
281 
282   if (!memory_tracker_lock_mutex()) {
283     p = memory_tracker_find(addr);
284     memory_tracker_unlock_mutex();
285   }
286 
287   return p;
288 }
289 
290 /*
291     vpx_memory_tracker_dump()
292     Locks the memory tracker's mutex and calls the internal
293     library function to dump the current contents of the
294     global memory allocation list
295 */
vpx_memory_tracker_dump()296 void vpx_memory_tracker_dump() {
297   if (!memory_tracker_lock_mutex()) {
298     memory_tracker_dump();
299     memory_tracker_unlock_mutex();
300   }
301 }
302 
303 /*
304     vpx_memory_tracker_check_integrity(char* file, unsigned int line)
305       file - The file name where the check was placed
306       line - The line in file where the check was placed
307     Locks the memory tracker's mutex and calls the internal
308     integrity check function to inspect every address in the global
309     memory allocation list
310 */
vpx_memory_tracker_check_integrity(char * file,unsigned int line)311 void vpx_memory_tracker_check_integrity(char *file, unsigned int line) {
312   if (!memory_tracker_lock_mutex()) {
313     memory_tracker_check_integrity(file, line);
314     memory_tracker_unlock_mutex();
315   }
316 }
317 
318 /*
319     vpx_memory_tracker_set_log_type
320     Sets the logging type for the memory tracker. Based on the value it will
321     direct its output to the appropriate place.
322     Return:
323       0: on success
324       -1: if the logging type could not be set, because the value was invalid
325           or because a file could not be opened
326 */
vpx_memory_tracker_set_log_type(int type,char * option)327 int vpx_memory_tracker_set_log_type(int type, char *option) {
328   int ret = -1;
329 
330   switch (type) {
331     case 0:
332       g_logging.type = 0;
333 
334       if (!option) {
335         g_logging.file = stderr;
336         ret = 0;
337       } else {
338         if ((g_logging.file = fopen((char *)option, "w")))
339           ret = 0;
340       }
341 
342       break;
343 #if defined(WIN32) && !defined(_WIN32_WCE)
344     case 1:
345       g_logging.type = type;
346       ret = 0;
347       break;
348 #endif
349     default:
350       break;
351   }
352 
353   // output the version to the new logging destination
354   if (!ret)
355     memtrack_log("Memory Tracker logging initialized, "
356                  "Memory Tracker v."vpx_mem_tracker_version"\n");
357 
358   return ret;
359 }
360 
361 /*
362     vpx_memory_tracker_set_log_func
363     Sets a logging function to be used by the memory tracker.
364     Return:
365       0: on success
366       -1: if the logging type could not be set because logfunc was NULL
367 */
vpx_memory_tracker_set_log_func(void * userdata,void (* logfunc)(void * userdata,const char * fmt,va_list args))368 int vpx_memory_tracker_set_log_func(void *userdata,
369                                     void(*logfunc)(void *userdata,
370                                                    const char *fmt, va_list args)) {
371   int ret = -1;
372 
373   if (logfunc) {
374     g_logging.type     = -1;
375     g_logging.userdata = userdata;
376     g_logging.func     = logfunc;
377     ret = 0;
378   }
379 
380   // output the version to the new logging destination
381   if (!ret)
382     memtrack_log("Memory Tracker logging initialized, "
383                  "Memory Tracker v."vpx_mem_tracker_version"\n");
384 
385   return ret;
386 }
387 
388 /*
389  *
390  * END - Exposed library functions
391  *
392 */
393 
394 
395 /*
396  *
397  * Internal library functions
398  *
399 */
400 
memtrack_log(const char * fmt,...)401 static void memtrack_log(const char *fmt, ...) {
402   va_list list;
403 
404   va_start(list, fmt);
405 
406   switch (g_logging.type) {
407     case -1:
408 
409       if (g_logging.func)
410         g_logging.func(g_logging.userdata, fmt, list);
411 
412       break;
413     case 0:
414 
415       if (g_logging.file) {
416         vfprintf(g_logging.file, fmt, list);
417         fflush(g_logging.file);
418       }
419 
420       break;
421 #if defined(WIN32) && !defined(_WIN32_WCE)
422     case 1: {
423       char temp[1024];
424       _vsnprintf(temp, sizeof(temp) / sizeof(char) - 1, fmt, list);
425       OutputDebugString(temp);
426     }
427     break;
428 #endif
429     default:
430       break;
431   }
432 
433   va_end(list);
434 }
435 
436 /*
437     memory_tracker_dump()
438     Dumps the current contents of the global memory allocation list
439 */
memory_tracker_dump()440 static void memory_tracker_dump() {
441   int i = 0;
442   struct mem_block *p = (memtrack.head ? memtrack.head->next : NULL);
443 
444   memtrack_log("\n_currently Allocated= %d; Max allocated= %d\n",
445                memtrack.current_allocated, memtrack.max_allocated);
446 
447   while (p) {
448 #if defined(WIN32) && !defined(_WIN32_WCE)
449 
450     /*when using outputdebugstring, output filenames so they
451       can be clicked to be opened in visual studio*/
452     if (g_logging.type == 1)
453       memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file:\n"
454                    "  %s(%d):\n", i,
455                    p->addr, i, p->size,
456                    p->file, p->line);
457     else
458 #endif
459       memtrack_log("memblocks[%d].addr= 0x%.8x, memblocks[%d].size= %d, file: %s, line: %d\n", i,
460                    p->addr, i, p->size,
461                    p->file, p->line);
462 
463     p = p->next;
464     ++i;
465   }
466 
467   memtrack_log("\n");
468 }
469 
470 /*
471     memory_tracker_check_integrity(char* file, unsigned int file)
472       file - the file name where the check was placed
473       line - the line in file where the check was placed
474     If a padding_size was supplied to vpx_memory_tracker_init()
475     this function will check ea. addr in the list verifying that
476     addr-padding_size and addr+padding_size is filled with pad_value
477 */
memory_tracker_check_integrity(char * file,unsigned int line)478 static void memory_tracker_check_integrity(char *file, unsigned int line) {
479   if (memtrack.padding_size) {
480     int i,
481         index = 0;
482     unsigned char *p_show_me,
483              * p_show_me2;
484     unsigned int tempme = memtrack.pad_value,
485                  dead1,
486                  dead2;
487     unsigned char *x_bounds;
488     struct mem_block *p = memtrack.head->next;
489 
490     while (p) {
491       // x_bounds = (unsigned char*)p->addr;
492       // back up VPX_BYTE_ALIGNMENT
493       // x_bounds -= memtrack.padding_size;
494 
495       if (p->padded) { // can the bounds be checked?
496         /*yes, move to the address that was actually allocated
497         by the vpx_* calls*/
498         x_bounds = (unsigned char *)(((size_t *)p->addr)[-1]);
499 
500         for (i = 0; i < memtrack.padding_size; i += sizeof(unsigned int)) {
501           p_show_me = (x_bounds + i);
502           p_show_me2 = (unsigned char *)(p->addr + p->size + i);
503 
504           MEM_TRACK_MEMCPY(&dead1, p_show_me, sizeof(unsigned int));
505           MEM_TRACK_MEMCPY(&dead2, p_show_me2, sizeof(unsigned int));
506 
507           if ((dead1 != tempme) || (dead2 != tempme)) {
508             memtrack_log("\n[vpx_mem integrity check failed]:\n"
509                          "    index[%d,%d] {%s:%d} addr=0x%x, size=%d,"
510                          " file: %s, line: %d c0:0x%x c1:0x%x\n",
511                          index, i, file, line, p->addr, p->size, p->file,
512                          p->line, dead1, dead2);
513           }
514         }
515       }
516 
517       ++index;
518       p = p->next;
519     }
520   }
521 }
522 
523 /*
524     memory_tracker_add(size_t addr, unsigned int size,
525                      char * file, unsigned int line)
526     Adds an address (addr), it's size, file and line number to our list.
527     Adjusts the total bytes allocated and max bytes allocated if necessary.
528     If memory cannot be allocated the list will be destroyed.
529 */
memory_tracker_add(size_t addr,unsigned int size,char * file,unsigned int line,int padded)530 void memory_tracker_add(size_t addr, unsigned int size,
531                         char *file, unsigned int line,
532                         int padded) {
533   if (!memory_tracker_lock_mutex()) {
534     struct mem_block *p;
535 
536     p = MEM_TRACK_MALLOC(sizeof(struct mem_block));
537 
538     if (p) {
539       p->prev       = memtrack.tail;
540       p->prev->next = p;
541       p->addr       = addr;
542       p->size       = size;
543       p->line       = line;
544       p->file       = file;
545       p->padded     = padded;
546       p->next       = NULL;
547 
548       memtrack.tail = p;
549 
550       memtrack.current_allocated += size;
551 
552       if (memtrack.current_allocated > memtrack.max_allocated)
553         memtrack.max_allocated = memtrack.current_allocated;
554 
555       // memtrack_log("memory_tracker_add: added addr=0x%.8x\n", addr);
556 
557       memory_tracker_unlock_mutex();
558     } else {
559       memtrack_log("memory_tracker_add: error allocating memory!\n");
560       memory_tracker_unlock_mutex();
561       vpx_memory_tracker_destroy();
562     }
563   }
564 }
565 
566 /*
567     memory_tracker_remove(size_t addr)
568     Removes an address and its corresponding size (if they exist)
569     from the memory tracker list and adjusts the current number
570     of bytes allocated.
571     Return:
572       0: on success
573       -1: if the mutex could not be locked
574       -2: if the addr was not found in the list
575 */
memory_tracker_remove(size_t addr)576 int memory_tracker_remove(size_t addr) {
577   int ret = -1;
578 
579   if (!memory_tracker_lock_mutex()) {
580     struct mem_block *p;
581 
582     if ((p = memory_tracker_find(addr))) {
583       memtrack.current_allocated -= p->size;
584 
585       p->prev->next = p->next;
586 
587       if (p->next)
588         p->next->prev = p->prev;
589       else
590         memtrack.tail = p->prev;
591 
592       ret = 0;
593       MEM_TRACK_FREE(p);
594     } else {
595       if (addr)
596         memtrack_log("memory_tracker_remove(): addr not found in list,"
597                      " 0x%.8x\n", addr);
598 
599       ret = -2;
600     }
601 
602     memory_tracker_unlock_mutex();
603   }
604 
605   return ret;
606 }
607 
608 /*
609     memory_tracker_find(size_t addr)
610     Finds an address in our addrs list
611     NOTE: the mutex MUST be locked in the other internal
612           functions before calling this one. This avoids
613           the need for repeated locking and unlocking as in Remove
614     Returns: pointer to the mem block if found, NULL otherwise
615 */
memory_tracker_find(size_t addr)616 static struct mem_block *memory_tracker_find(size_t addr) {
617   struct mem_block *p = NULL;
618 
619   if (memtrack.head) {
620     p = memtrack.head->next;
621 
622     while (p && (p->addr != addr))
623       p = p->next;
624   }
625 
626   return p;
627 }
628 
629 
630 #if !defined(NO_MUTEX)
631 /*
632     memory_tracker_lock_mutex()
633     Locks the memory tracker mutex with a platform specific call
634     Returns:
635         0: Success
636        <0: Failure, either the mutex was not initialized
637            or the call to lock the mutex failed
638 */
memory_tracker_lock_mutex()639 static int memory_tracker_lock_mutex() {
640   int ret = -1;
641 
642   if (g_b_mem_tracker_inited) {
643 
644 #if HAVE_PTHREAD_H
645     ret = pthread_mutex_lock(&memtrack.mutex);
646 #elif defined(WIN32) || defined(_WIN32_WCE)
647     ret = WaitForSingleObject(memtrack.mutex, INFINITE);
648 #elif defined(VXWORKS)
649     ret = sem_take(memtrack.mutex, WAIT_FOREVER);
650 #endif
651 
652     if (ret) {
653       memtrack_log("memory_tracker_lock_mutex: mutex lock failed\n");
654     }
655   }
656 
657   return ret;
658 }
659 
660 /*
661     memory_tracker_unlock_mutex()
662     Unlocks the memory tracker mutex with a platform specific call
663     Returns:
664         0: Success
665        <0: Failure, either the mutex was not initialized
666            or the call to unlock the mutex failed
667 */
memory_tracker_unlock_mutex()668 static int memory_tracker_unlock_mutex() {
669   int ret = -1;
670 
671   if (g_b_mem_tracker_inited) {
672 
673 #if HAVE_PTHREAD_H
674     ret = pthread_mutex_unlock(&memtrack.mutex);
675 #elif defined(WIN32) || defined(_WIN32_WCE)
676     ret = !ReleaseMutex(memtrack.mutex);
677 #elif defined(VXWORKS)
678     ret = sem_give(memtrack.mutex);
679 #endif
680 
681     if (ret) {
682       memtrack_log("memory_tracker_unlock_mutex: mutex unlock failed\n");
683     }
684   }
685 
686   return ret;
687 }
688 #endif
689 
690 /*
691     vpx_memory_tracker_set_functions
692 
693     Sets the function pointers for the standard library functions.
694 
695     Return:
696       0: on success
697       -1: if the use global function pointers is not set.
698 */
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)699 int vpx_memory_tracker_set_functions(mem_track_malloc_func g_malloc_l
700 , mem_track_calloc_func g_calloc_l
701 , mem_track_realloc_func g_realloc_l
702 , mem_track_free_func g_free_l
703 , mem_track_memcpy_func g_memcpy_l
704 , mem_track_memset_func g_memset_l
705 , mem_track_memmove_func g_memmove_l) {
706 #if USE_GLOBAL_FUNCTION_POINTERS
707 
708   if (g_malloc_l)
709     g_malloc = g_malloc_l;
710 
711   if (g_calloc_l)
712     g_calloc = g_calloc_l;
713 
714   if (g_realloc_l)
715     g_realloc = g_realloc_l;
716 
717   if (g_free_l)
718     g_free = g_free_l;
719 
720   if (g_memcpy_l)
721     g_memcpy = g_memcpy_l;
722 
723   if (g_memset_l)
724     g_memset = g_memset_l;
725 
726   if (g_memmove_l)
727     g_memmove = g_memmove_l;
728 
729   return 0;
730 #else
731   (void)g_malloc_l;
732   (void)g_calloc_l;
733   (void)g_realloc_l;
734   (void)g_free_l;
735   (void)g_memcpy_l;
736   (void)g_memset_l;
737   (void)g_memmove_l;
738   return -1;
739 #endif
740 }
741