Alloc.c revision fdf6a26f
1/***********************************************************
2Copyright (c) 1993, 2023, Oracle and/or its affiliates.
3
4Permission is hereby granted, free of charge, to any person obtaining a
5copy of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation
7the rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the
9Software is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice (including the next
12paragraph) shall be included in all copies or substantial portions of the
13Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21DEALINGS IN THE SOFTWARE.
22
23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24
25                        All Rights Reserved
26
27Permission to use, copy, modify, and distribute this software and its
28documentation for any purpose and without fee is hereby granted,
29provided that the above copyright notice appear in all copies and that
30both that copyright notice and this permission notice appear in
31supporting documentation, and that the name of Digital not be
32used in advertising or publicity pertaining to distribution of the
33software without specific, written prior permission.
34
35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41SOFTWARE.
42
43******************************************************************/
44
45/*
46
47Copyright 1987, 1988, 1998  The Open Group
48
49Permission to use, copy, modify, distribute, and sell this software and its
50documentation for any purpose is hereby granted without fee, provided that
51the above copyright notice appear in all copies and that both that
52copyright notice and this permission notice appear in supporting
53documentation.
54
55The above copyright notice and this permission notice shall be included in
56all copies or substantial portions of the Software.
57
58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64
65Except as contained in this notice, the name of The Open Group shall not be
66used in advertising or otherwise to promote the sale, use or other dealings
67in 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
95void
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
111void
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
122void
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 */
133Cardinal
134XtAsprintf(_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
165char *
166XtMalloc(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
181char *
182XtRealloc(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
201void *
202XtReallocArray(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
233char *
234XtCalloc(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
249void
250XtFree(char *ptr)
251{
252    free(ptr);
253}
254
255char *
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
265char *
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
279char *
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
321void
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
347typedef struct _Stats *StatsPtr;
348typedef 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
357static StatsPtr XtMemory = (StatsPtr) NULL;
358static unsigned long ActiveXtMemory = 0;
359static unsigned long XtSeqId = 0;
360static 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*/
384static void
385_XtBreakpoint(StatsPtr mem)
386{
387    mem->seq = XtSeqId;         /* avoid being optimized out of existence */
388}
389
390char *
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
407char *
408XtMalloc(unsigned size)
409{
410    return _XtMalloc(size, (char *) NULL, 0);
411}
412
413char *
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
432char *
433XtRealloc(char *ptr, unsigned size)
434{
435    return _XtRealloc(ptr, size, (char *) NULL, 0);
436}
437
438void *
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
449void *
450XtReallocArray(void *ptr, unsigned num, unsigned size)
451{
452    return _XtReallocArray(ptr, num, size, (char *) NULL, 0);
453}
454
455char *
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
473char *
474XtCalloc(unsigned num, unsigned size)
475{
476    return _XtCalloc(num, size, (char *) NULL, 0);
477}
478
479Boolean
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
496Boolean _XtValidateMemory = False;
497
498void
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
521void
522XtFree(char *ptr)
523{
524    _XtFree(ptr);
525}
526
527char *
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
545void
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
570void
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