Home | History | Annotate | Line # | Download | only in src
      1 /***********************************************************
      2 Copyright (c) 1993, 2023, Oracle and/or its affiliates.
      3 
      4 Permission is hereby granted, free of charge, to any person obtaining a
      5 copy of this software and associated documentation files (the "Software"),
      6 to deal in the Software without restriction, including without limitation
      7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 and/or sell copies of the Software, and to permit persons to whom the
      9 Software is furnished to do so, subject to the following conditions:
     10 
     11 The above copyright notice and this permission notice (including the next
     12 paragraph) shall be included in all copies or substantial portions of the
     13 Software.
     14 
     15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21 DEALINGS IN THE SOFTWARE.
     22 
     23 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
     24 
     25                         All Rights Reserved
     26 
     27 Permission to use, copy, modify, and distribute this software and its
     28 documentation for any purpose and without fee is hereby granted,
     29 provided that the above copyright notice appear in all copies and that
     30 both that copyright notice and this permission notice appear in
     31 supporting documentation, and that the name of Digital not be
     32 used in advertising or publicity pertaining to distribution of the
     33 software without specific, written prior permission.
     34 
     35 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     36 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     37 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     38 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     39 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     40 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     41 SOFTWARE.
     42 
     43 ******************************************************************/
     44 
     45 /*
     46 
     47 Copyright 1987, 1988, 1998  The Open Group
     48 
     49 Permission to use, copy, modify, distribute, and sell this software and its
     50 documentation for any purpose is hereby granted without fee, provided that
     51 the above copyright notice appear in all copies and that both that
     52 copyright notice and this permission notice appear in supporting
     53 documentation.
     54 
     55 The above copyright notice and this permission notice shall be included in
     56 all copies or substantial portions of the Software.
     57 
     58 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     59 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     60 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     61 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     62 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     63 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     64 
     65 Except as contained in this notice, the name of The Open Group shall not be
     66 used in advertising or otherwise to promote the sale, use or other dealings
     67 in this Software without prior written authorization from The Open Group.
     68 
     69 */
     70 
     71 /*
     72  * X Toolkit Memory Allocation Routines
     73  *
     74  * Uses Xlib memory management, which is spec'd to be re-entrant.
     75  */
     76 
     77 #ifdef HAVE_CONFIG_H
     78 #include <config.h>
     79 #endif
     80 #include "IntrinsicI.h"
     81 #include "InitialI.h"
     82 #undef _XBCOPYFUNC
     83 
     84 #include <stdlib.h>
     85 #include <stdio.h>
     86 #include <stdarg.h>
     87 #include <limits.h>
     88 
     89 #define Xmalloc(size) malloc((size))
     90 #define Xrealloc(ptr, size) realloc((ptr), (size))
     91 #define Xcalloc(nelem, elsize) calloc((nelem), (elsize))
     92 #define Xfree(ptr) free(ptr)
     93 
     94 #ifdef _XNEEDBCOPYFUNC
     95 void
     96 _XtBcopy(char *src, char *dst, int length)
     97 {
     98     if (src < dst) {
     99         dst += length;
    100         src += length;
    101         while (length--)
    102             *--dst = *--src;
    103     }
    104     else {
    105         while (length--)
    106             *dst++ = *src++;
    107     }
    108 }
    109 #endif
    110 
    111 void
    112 _XtAllocError(String type)
    113 {
    114     Cardinal num_params = 1;
    115 
    116     if (type == NULL)
    117         type = "local memory allocation";
    118     XtErrorMsg("allocError", type, XtCXtToolkitError,
    119                "Cannot perform %s", &type, &num_params);
    120 }
    121 
    122 void
    123 _XtHeapInit(Heap *heap)
    124 {
    125     heap->start = NULL;
    126     heap->bytes_remaining = 0;
    127 }
    128 
    129 /* Version of asprintf() using XtMalloc
    130  * Not currently available in XTTRACEMEMORY version, since that would
    131  * require varargs macros everywhere, which are only standard in C99 & later.
    132  */
    133 Cardinal
    134 XtAsprintf(_XtString *new_string, _Xconst char *_X_RESTRICT_KYWD format, ...)
    135 {
    136     char buf[256];
    137     int len;
    138     va_list ap;
    139 
    140     va_start(ap, format);
    141     len = vsnprintf(buf, sizeof(buf), format, ap);
    142     va_end(ap);
    143 
    144     if (len < 0)
    145         _XtAllocError("vsnprintf");
    146 
    147     *new_string = XtMalloc((Cardinal) len + 1); /* snprintf doesn't count trailing '\0' */
    148     if ((size_t) len < sizeof(buf)) {
    149         if ((size_t) len > 0) {
    150             memcpy(*new_string, buf, (size_t) len);
    151         }
    152         (*new_string)[len] = '\0';
    153     }
    154     else {
    155         va_start(ap, format);
    156         if (vsnprintf(*new_string, (size_t) (len + 1), format, ap) < 0)
    157             _XtAllocError("vsnprintf");
    158         va_end(ap);
    159     }
    160     return (Cardinal) len;
    161 }
    162 
    163 #ifndef XTTRACEMEMORY
    164 
    165 char *
    166 XtMalloc(unsigned size)
    167 {
    168     char *ptr;
    169 
    170 #if defined(MALLOC_0_RETURNS_NULL) && defined(XTMALLOC_BC)
    171     /* preserve this (broken) behavior until everyone fixes their apps */
    172     if (!size)
    173         size = 1;
    174 #endif
    175     if ((ptr = Xmalloc(size)) == NULL)
    176         _XtAllocError("malloc");
    177 
    178     return (ptr);
    179 }
    180 
    181 char *
    182 XtRealloc(char *ptr, unsigned size)
    183 {
    184     if (ptr == NULL) {
    185 #ifdef MALLOC_0_RETURNS_NULL
    186         if (!size)
    187             size = 1;
    188 #endif
    189         return (XtMalloc(size));
    190     }
    191     else if ((ptr = Xrealloc(ptr, size)) == NULL
    192 #ifdef MALLOC_0_RETURNS_NULL
    193              && size
    194 #endif
    195         )
    196         _XtAllocError("realloc");
    197 
    198     return (ptr);
    199 }
    200 
    201 void *
    202 XtReallocArray(void *ptr, unsigned num, unsigned size)
    203 {
    204     if (ptr == NULL) {
    205 #ifdef MALLOC_0_RETURNS_NULL
    206         if ((num == 0) || (size == 0))
    207             num = size = 1;
    208 #endif
    209 #if (SIZE_MAX / UINT_MAX) <= UINT_MAX
    210         if ((num > 0) && (SIZE_MAX / num) < size)
    211             _XtAllocError("reallocarray: overflow detected");
    212 #endif
    213         return (XtMalloc(num * size));
    214     }
    215     else {
    216         void *new;
    217 
    218 #ifdef HAVE_REALLOCARRAY
    219         new = reallocarray(ptr, size, num);
    220 #else
    221 # if (SIZE_MAX / UINT_MAX) <= UINT_MAX
    222         if ((num > 0) && ((SIZE_MAX / num) < size))
    223             _XtAllocError("reallocarray: overflow detected");
    224 # endif
    225         new = Xrealloc(ptr, size * num);
    226 #endif
    227         if ((new == NULL) && (num != 0) && (size != 0))
    228             _XtAllocError("reallocarray");
    229         return (new);
    230     }
    231 }
    232 
    233 char *
    234 XtCalloc(unsigned num, unsigned size)
    235 {
    236     char *ptr;
    237 
    238 #if defined(MALLOC_0_RETURNS_NULL) && defined(XTMALLOC_BC)
    239     /* preserve this (broken) behavior until everyone fixes their apps */
    240     if (!size)
    241         num = size = 1;
    242 #endif
    243     if ((ptr = Xcalloc(num, size)) == NULL)
    244         _XtAllocError("calloc");
    245 
    246     return (ptr);
    247 }
    248 
    249 void
    250 XtFree(char *ptr)
    251 {
    252     free(ptr);
    253 }
    254 
    255 char *
    256 __XtMalloc(unsigned size)
    257 {
    258 #ifdef MALLOC_0_RETURNS_NULL
    259     if (!size)
    260         size = 1;
    261 #endif
    262     return XtMalloc(size);
    263 }
    264 
    265 char *
    266 __XtCalloc(unsigned num, unsigned size)
    267 {
    268 #ifdef MALLOC_0_RETURNS_NULL
    269     if (!size)
    270         num = size = 1;
    271 #endif
    272     return XtCalloc(num, size);
    273 }
    274 
    275 #ifndef HEAP_SEGMENT_SIZE
    276 #define HEAP_SEGMENT_SIZE 1492
    277 #endif
    278 
    279 char *
    280 _XtHeapAlloc(Heap *heap, Cardinal bytes)
    281 {
    282     register char *heap_loc;
    283 
    284     if (heap == NULL)
    285         return XtMalloc(bytes);
    286     if (heap->bytes_remaining < (int) bytes) {
    287         if ((bytes + sizeof(char *)) >= (HEAP_SEGMENT_SIZE >> 1)) {
    288             /* preserve current segment; insert this one in front */
    289 #ifdef _TRACE_HEAP
    290             printf("allocating large segment (%d bytes) on heap %p\n",
    291                    bytes, heap);
    292 #endif
    293             heap_loc = XtMalloc(bytes + (Cardinal) sizeof(char *));
    294             if (heap->start) {
    295                 *(char **) heap_loc = *(char **) heap->start;
    296                 *(char **) heap->start = heap_loc;
    297             }
    298             else {
    299                 *(char **) heap_loc = NULL;
    300                 heap->start = heap_loc;
    301             }
    302             return heap_loc + sizeof(char *);
    303         }
    304         /* else discard remainder of this segment */
    305 #ifdef _TRACE_HEAP
    306         printf("allocating new segment on heap %p\n", heap);
    307 #endif
    308         heap_loc = XtMalloc((unsigned) HEAP_SEGMENT_SIZE);
    309         *(char **) heap_loc = heap->start;
    310         heap->start = heap_loc;
    311         heap->current = heap_loc + sizeof(char *);
    312         heap->bytes_remaining = HEAP_SEGMENT_SIZE - sizeof(char *);
    313     }
    314     bytes = (Cardinal) ((bytes + (sizeof(long) - 1)) & (~(sizeof(long) - 1)));
    315     heap_loc = heap->current;
    316     heap->current += bytes;
    317     heap->bytes_remaining = (heap->bytes_remaining - (int) bytes);      /* can be negative, if rounded */
    318     return heap_loc;
    319 }
    320 
    321 void
    322 _XtHeapFree(Heap *heap)
    323 {
    324     char *segment = heap->start;
    325 
    326     while (segment != NULL) {
    327         char *next_segment = *(char **) segment;
    328 
    329         XtFree(segment);
    330         segment = next_segment;
    331     }
    332     heap->start = NULL;
    333     heap->bytes_remaining = 0;
    334 }
    335 
    336 #else
    337 
    338 /*
    339  * X Toolkit Memory Trace Allocation Routines
    340  */
    341 
    342 #undef XtMalloc
    343 #undef XtRealloc
    344 #undef XtCalloc
    345 #undef XtFree
    346 
    347 typedef struct _Stats *StatsPtr;
    348 typedef struct _Stats {
    349     StatsPtr prev, next;
    350     const char *file;
    351     int line;
    352     unsigned size;
    353     unsigned long seq;
    354     XtPointer heap;
    355 } Stats;
    356 
    357 static StatsPtr XtMemory = (StatsPtr) NULL;
    358 static unsigned long ActiveXtMemory = 0;
    359 static unsigned long XtSeqId = 0;
    360 static unsigned long XtSeqBreakpoint = (unsigned long) (~0UL);
    361 
    362 #define StatsSize(n) (unsigned)((((n) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) + sizeof(Stats))
    363 #define ToStats(ptr) ((StatsPtr)(ptr - sizeof(Stats)))
    364 #define ToMem(ptr) (((char *)ptr) + sizeof(Stats))
    365 
    366 #define CHAIN(ptr,len,hp) \
    367     ptr->next = XtMemory; \
    368     if (XtMemory) \
    369         XtMemory->prev = ptr; \
    370     XtMemory = ptr; \
    371     ptr->prev = (StatsPtr)NULL; \
    372     ptr->file = file; \
    373     ptr->line = line; \
    374     ptr->size = len; \
    375     ptr->heap = hp; \
    376     if (file) \
    377         ActiveXtMemory += len; \
    378     ptr->seq = XtSeqId; \
    379     if (XtSeqId == XtSeqBreakpoint) \
    380         _XtBreakpoint(ptr); \
    381     XtSeqId++
    382 
    383 /*ARGUSED*/
    384 static void
    385 _XtBreakpoint(StatsPtr mem)
    386 {
    387     mem->seq = XtSeqId;         /* avoid being optimized out of existence */
    388 }
    389 
    390 char *
    391 _XtMalloc(unsigned size, const char *file, int line)
    392 {
    393     StatsPtr ptr;
    394     unsigned newsize;
    395     char *retval = NULL;
    396 
    397     LOCK_PROCESS;
    398     newsize = StatsSize(size);
    399     if ((ptr = (StatsPtr) Xmalloc(newsize)) == NULL)
    400         _XtAllocError("malloc");
    401     CHAIN(ptr, size, NULL);
    402     retval = (ToMem(ptr));
    403     UNLOCK_PROCESS;
    404     return retval;
    405 }
    406 
    407 char *
    408 XtMalloc(unsigned size)
    409 {
    410     return _XtMalloc(size, (char *) NULL, 0);
    411 }
    412 
    413 char *
    414 _XtRealloc(char *ptr, unsigned size, const char *file, int line)
    415 {
    416     char *newptr;
    417 
    418     LOCK_PROCESS;
    419     newptr = _XtMalloc(size, file, line);
    420     if (ptr) {
    421         unsigned copysize = ToStats(ptr)->size;
    422 
    423         if (copysize > size)
    424             copysize = size;
    425         memcpy(newptr, ptr, copysize);
    426         _XtFree(ptr);
    427     }
    428     UNLOCK_PROCESS;
    429     return (newptr);
    430 }
    431 
    432 char *
    433 XtRealloc(char *ptr, unsigned size)
    434 {
    435     return _XtRealloc(ptr, size, (char *) NULL, 0);
    436 }
    437 
    438 void *
    439 _XtReallocArray(void *ptr, unsigned num, unsigned size, const char *file, int line)
    440 {
    441 #if (SIZE_MAX / UINT_MAX) <= UINT_MAX
    442     if ((num > 0) && (SIZE_MAX / num) < size)
    443         _XtAllocError("reallocarray: overflow");
    444 #endif
    445 
    446     return _XtRealloc(ptr, (num * size), file, line);
    447 }
    448 
    449 void *
    450 XtReallocArray(void *ptr, unsigned num, unsigned size)
    451 {
    452     return _XtReallocArray(ptr, num, size, (char *) NULL, 0);
    453 }
    454 
    455 char *
    456 _XtCalloc(unsigned num, unsigned size, const char *file, int line)
    457 {
    458     StatsPtr ptr;
    459     unsigned total, newsize;
    460     char *retval = NULL;
    461 
    462     LOCK_PROCESS;
    463     total = num * size;
    464     newsize = StatsSize(total);
    465     if ((ptr = (StatsPtr) Xcalloc(newsize, 1)) == NULL)
    466         _XtAllocError("calloc");
    467     CHAIN(ptr, total, NULL);
    468     retval = (ToMem(ptr));
    469     UNLOCK_PROCESS;
    470     return retval;
    471 }
    472 
    473 char *
    474 XtCalloc(unsigned num, unsigned size)
    475 {
    476     return _XtCalloc(num, size, (char *) NULL, 0);
    477 }
    478 
    479 Boolean
    480 _XtIsValidPointer(char *ptr)
    481 {
    482     register StatsPtr mem;
    483     register StatsPtr stp = ToStats(ptr);
    484 
    485     LOCK_PROCESS;
    486     for (mem = XtMemory; mem; mem = mem->next) {
    487         if (mem == stp) {
    488             UNLOCK_PROCESS;
    489             return True;
    490         }
    491     }
    492     UNLOCK_PROCESS;
    493     return False;
    494 }
    495 
    496 Boolean _XtValidateMemory = False;
    497 
    498 void
    499 _XtFree(char *ptr)
    500 {
    501     register StatsPtr stp;
    502 
    503     LOCK_PROCESS;
    504     if (ptr) {
    505         if (_XtValidateMemory && !_XtIsValidPointer(ptr))
    506             abort();
    507         stp = ToStats(ptr);
    508         if (stp->file)
    509             ActiveXtMemory -= stp->size;
    510         if (stp->prev)
    511             stp->prev->next = stp->next;
    512         else
    513             XtMemory = stp->next;
    514         if (stp->next)
    515             stp->next->prev = stp->prev;
    516         Xfree((char *) stp);
    517     }
    518     UNLOCK_PROCESS;
    519 }
    520 
    521 void
    522 XtFree(char *ptr)
    523 {
    524     _XtFree(ptr);
    525 }
    526 
    527 char *
    528 _XtHeapMalloc(Heap *heap, Cardinal size, const char *file, int line)
    529 {
    530     StatsPtr ptr;
    531     unsigned newsize;
    532     XtPointer hp = (XtPointer) heap;
    533     char *retval = NULL;
    534 
    535     LOCK_PROCESS;
    536     newsize = StatsSize(size);
    537     if ((ptr = (StatsPtr) Xmalloc(newsize)) == NULL)
    538         _XtAllocError("malloc");
    539     CHAIN(ptr, size, hp);
    540     retval = (ToMem(ptr));
    541     UNLOCK_PROCESS;
    542     return retval;
    543 }
    544 
    545 void
    546 _XtHeapFree(Heap *heap)
    547 {
    548     register StatsPtr mem, next;
    549 
    550     LOCK_PROCESS;
    551     for (mem = XtMemory; mem; mem = next) {
    552         next = mem->next;
    553         if (mem->heap == heap) {
    554             if (mem->file)
    555                 ActiveXtMemory -= mem->size;
    556             if (mem->prev)
    557                 mem->prev->next = next;
    558             else
    559                 XtMemory = next;
    560             if (next)
    561                 next->prev = mem->prev;
    562             Xfree((char *) mem);
    563         }
    564     }
    565     UNLOCK_PROCESS;
    566 }
    567 
    568 #include <stdio.h>
    569 
    570 void
    571 _XtPrintMemory(const char *filename)
    572 {
    573     register StatsPtr mem;
    574     FILE *f;
    575 
    576     if (filename == NULL)
    577         f = stderr;
    578     else
    579         f = fopen(filename, "w");
    580     LOCK_PROCESS;
    581     fprintf(f, "total size: %lu\n", ActiveXtMemory);
    582     for (mem = XtMemory; mem; mem = mem->next) {
    583         if (mem->file)
    584             fprintf(f, "size: %6d  seq: %5lu  %12s(%4d)  %s\n",
    585                     mem->size, mem->seq,
    586                     mem->file, mem->line, mem->heap ? "heap" : "");
    587     }
    588     UNLOCK_PROCESS;
    589     if (filename)
    590         fclose(f);
    591 }
    592 
    593 #endif                          /* XTTRACEMEMORY */
    594