1*cb63e24eSchristos /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
24f645668Schristos Contributed by Oracle.
34f645668Schristos
44f645668Schristos This file is part of GNU Binutils.
54f645668Schristos
64f645668Schristos This program is free software; you can redistribute it and/or modify
74f645668Schristos it under the terms of the GNU General Public License as published by
84f645668Schristos the Free Software Foundation; either version 3, or (at your option)
94f645668Schristos any later version.
104f645668Schristos
114f645668Schristos This program is distributed in the hope that it will be useful,
124f645668Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
134f645668Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
144f645668Schristos GNU General Public License for more details.
154f645668Schristos
164f645668Schristos You should have received a copy of the GNU General Public License
174f645668Schristos along with this program; if not, write to the Free Software
184f645668Schristos Foundation, 51 Franklin Street - Fifth Floor, Boston,
194f645668Schristos MA 02110-1301, USA. */
204f645668Schristos
214f645668Schristos #include "config.h"
224f645668Schristos #include <dlfcn.h>
234f645668Schristos #include "util.h"
244f645668Schristos
254f645668Schristos #define CHECK_OUT_OF_MEM(ptr, size) if (ptr == NULL) err_out_of_memory(size)
264f645668Schristos
274f645668Schristos /* Report Out of Memory error and exit */
284f645668Schristos static void
err_out_of_memory(unsigned nbytes)294f645668Schristos err_out_of_memory (unsigned nbytes)
304f645668Schristos {
314f645668Schristos char *nm = get_prog_name (1);
324f645668Schristos if (nm)
334f645668Schristos fprintf (stderr, GTXT ("%s: Error: Memory capacity exceeded.\n"), nm);
344f645668Schristos else
354f645668Schristos fprintf (stderr, GTXT ("Error: Memory capacity exceeded.\n"));
364f645668Schristos fprintf (stderr, GTXT (" Requested %u bytes.\n"), nbytes);
374f645668Schristos exit (16);
384f645668Schristos }
394f645668Schristos
404f645668Schristos #define CALL_REAL(x) (__real_##x)
414f645668Schristos #define NULL_PTR(x) ( __real_##x == NULL )
424f645668Schristos
434f645668Schristos static void *(*__real_malloc)(size_t) = NULL;
444f645668Schristos static void (*__real_free)(void *) = NULL;
454f645668Schristos static void *(*__real_realloc)(void *, size_t) = NULL;
464f645668Schristos static void *(*__real_calloc)(size_t, size_t) = NULL;
474f645668Schristos static char *(*__real_strdup)(const char*) = NULL;
484f645668Schristos static volatile int in_init = 0;
494f645668Schristos
504f645668Schristos static int
init_heap_intf()514f645668Schristos init_heap_intf ()
524f645668Schristos {
534f645668Schristos in_init = 1;
544f645668Schristos __real_malloc = (void*(*)(size_t))dlsym (RTLD_NEXT, "malloc");
554f645668Schristos __real_free = (void(*)(void *))dlsym (RTLD_NEXT, "free");
564f645668Schristos __real_realloc = (void*(*)(void *, size_t))dlsym (RTLD_NEXT, "realloc");
574f645668Schristos __real_calloc = (void*(*)(size_t, size_t))dlsym (RTLD_NEXT, "calloc");
584f645668Schristos __real_strdup = (char*(*)(const char*))dlsym (RTLD_NEXT, "strdup");
594f645668Schristos in_init = 0;
604f645668Schristos return 0;
614f645668Schristos }
624f645668Schristos
634f645668Schristos /* --------------------------------------------------------------------------- */
644f645668Schristos /* libc's memory management functions substitutions */
654f645668Schristos
664f645668Schristos /* Allocate memory and make sure we got some */
674f645668Schristos void *
malloc(size_t size)684f645668Schristos malloc (size_t size)
694f645668Schristos {
704f645668Schristos if (NULL_PTR (malloc))
714f645668Schristos init_heap_intf ();
724f645668Schristos void *ptr = CALL_REAL (malloc)(size);
734f645668Schristos CHECK_OUT_OF_MEM (ptr, size);
744f645668Schristos return ptr;
754f645668Schristos }
764f645668Schristos
774f645668Schristos
784f645668Schristos /* Implement a workaround for a libdl recursion problem */
794f645668Schristos void *
calloc(size_t nelem,size_t size)804f645668Schristos calloc (size_t nelem, size_t size)
814f645668Schristos {
824f645668Schristos if (NULL_PTR (calloc))
834f645668Schristos {
844f645668Schristos /* If a program is linked with libpthread then the following
854f645668Schristos * calling sequence occurs:
864f645668Schristos * init_heap_intf -> dlsym -> calloc -> malloc -> init_heap_intf
874f645668Schristos * We break some performance improvement in libdl by returning
884f645668Schristos * NULL but preserve functionality.
894f645668Schristos */
904f645668Schristos if (in_init)
914f645668Schristos return NULL;
924f645668Schristos init_heap_intf ();
934f645668Schristos }
944f645668Schristos return CALL_REAL (calloc)(nelem, size);
954f645668Schristos }
964f645668Schristos
974f645668Schristos /* Free the storage associated with data */
984f645668Schristos void
free(void * ptr)994f645668Schristos free (void *ptr)
1004f645668Schristos {
1014f645668Schristos if (ptr == NULL)
1024f645668Schristos return;
1034f645668Schristos if (NULL_PTR (free))
1044f645668Schristos init_heap_intf ();
1054f645668Schristos CALL_REAL (free)(ptr);
1064f645668Schristos return;
1074f645668Schristos }
1084f645668Schristos
1094f645668Schristos /* Reallocate buffer */
1104f645668Schristos void *
realloc(void * ptr,size_t size)1114f645668Schristos realloc (void *ptr, size_t size)
1124f645668Schristos {
1134f645668Schristos if (NULL_PTR (realloc))
1144f645668Schristos init_heap_intf ();
1154f645668Schristos ptr = CALL_REAL (realloc)(ptr, size);
1164f645668Schristos CHECK_OUT_OF_MEM (ptr, size);
1174f645668Schristos return ptr;
1184f645668Schristos }
119