1 /***********************************************************
2 Copyright (c) 1993, 2011, Oracle and/or its affiliates. All rights reserved.
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 
88 #define Xmalloc(size) malloc((size))
89 #define Xrealloc(ptr, size) realloc((ptr), (size))
90 #define Xcalloc(nelem, elsize) calloc((nelem), (elsize))
91 #define Xfree(ptr) free(ptr)
92 
93 #ifdef _XNEEDBCOPYFUNC
94 void
_XtBcopy(char * src,char * dst,int length)95 _XtBcopy(char *src, char *dst, int length)
96 {
97     if (src < dst) {
98         dst += length;
99         src += length;
100         while (length--)
101             *--dst = *--src;
102     }
103     else {
104         while (length--)
105             *dst++ = *src++;
106     }
107 }
108 #endif
109 
110 void
_XtAllocError(String type)111 _XtAllocError(String type)
112 {
113     Cardinal num_params = 1;
114 
115     if (type == NULL)
116         type = "local memory allocation";
117     XtErrorMsg("allocError", type, XtCXtToolkitError,
118                "Cannot perform %s", &type, &num_params);
119 }
120 
121 void
_XtHeapInit(Heap * heap)122 _XtHeapInit(Heap *heap)
123 {
124     heap->start = NULL;
125     heap->bytes_remaining = 0;
126 }
127 
128 /* Version of asprintf() using XtMalloc
129  * Not currently available in XTTRACEMEMORY version, since that would
130  * require varargs macros everywhere, which are only standard in C99 & later.
131  */
132 Cardinal
XtAsprintf(_XtString * new_string,_Xconst char * _X_RESTRICT_KYWD format,...)133 XtAsprintf(_XtString *new_string, _Xconst char *_X_RESTRICT_KYWD format, ...)
134 {
135     char buf[256];
136     int len;
137     va_list ap;
138 
139     va_start(ap, format);
140     len = vsnprintf(buf, sizeof(buf), format, ap);
141     va_end(ap);
142 
143     if (len < 0)
144         _XtAllocError("vsnprintf");
145 
146     *new_string = XtMalloc((Cardinal) len + 1); /* snprintf doesn't count trailing '\0' */
147     if ((size_t) len < sizeof(buf)) {
148         strncpy(*new_string, buf, (size_t) len);
149         (*new_string)[len] = '\0';
150     }
151     else {
152         va_start(ap, format);
153         if (vsnprintf(*new_string, (size_t) (len + 1), format, ap) < 0)
154             _XtAllocError("vsnprintf");
155         va_end(ap);
156     }
157     return (Cardinal) len;
158 }
159 
160 #ifndef XTTRACEMEMORY
161 
162 char *
XtMalloc(unsigned size)163 XtMalloc(unsigned size)
164 {
165     char *ptr;
166 
167 #if defined(MALLOC_0_RETURNS_NULL) && defined(XTMALLOC_BC)
168     /* preserve this (broken) behavior until everyone fixes their apps */
169     if (!size)
170         size = 1;
171 #endif
172     if ((ptr = Xmalloc(size)) == NULL)
173         _XtAllocError("malloc");
174 
175     return (ptr);
176 }
177 
178 char *
XtRealloc(char * ptr,unsigned size)179 XtRealloc(char *ptr, unsigned size)
180 {
181     if (ptr == NULL) {
182 #ifdef MALLOC_0_RETURNS_NULL
183         if (!size)
184             size = 1;
185 #endif
186         return (XtMalloc(size));
187     }
188     else if ((ptr = Xrealloc(ptr, size)) == NULL
189 #ifdef MALLOC_0_RETURNS_NULL
190              && size
191 #endif
192         )
193         _XtAllocError("realloc");
194 
195     return (ptr);
196 }
197 
198 char *
XtCalloc(unsigned num,unsigned size)199 XtCalloc(unsigned num, unsigned size)
200 {
201     char *ptr;
202 
203 #if defined(MALLOC_0_RETURNS_NULL) && defined(XTMALLOC_BC)
204     /* preserve this (broken) behavior until everyone fixes their apps */
205     if (!size)
206         num = size = 1;
207 #endif
208     if ((ptr = Xcalloc(num, size)) == NULL)
209         _XtAllocError("calloc");
210 
211     return (ptr);
212 }
213 
214 void
XtFree(char * ptr)215 XtFree(char *ptr)
216 {
217     free(ptr);
218 }
219 
220 char *
__XtMalloc(unsigned size)221 __XtMalloc(unsigned size)
222 {
223 #ifdef MALLOC_0_RETURNS_NULL
224     if (!size)
225         size = 1;
226 #endif
227     return XtMalloc(size);
228 }
229 
230 char *
__XtCalloc(unsigned num,unsigned size)231 __XtCalloc(unsigned num, unsigned size)
232 {
233 #ifdef MALLOC_0_RETURNS_NULL
234     if (!size)
235         num = size = 1;
236 #endif
237     return XtCalloc(num, size);
238 }
239 
240 #ifndef HEAP_SEGMENT_SIZE
241 #define HEAP_SEGMENT_SIZE 1492
242 #endif
243 
244 char *
_XtHeapAlloc(Heap * heap,Cardinal bytes)245 _XtHeapAlloc(Heap *heap, Cardinal bytes)
246 {
247     register char *heap_loc;
248 
249     if (heap == NULL)
250         return XtMalloc(bytes);
251     if (heap->bytes_remaining < (int) bytes) {
252         if ((bytes + sizeof(char *)) >= (HEAP_SEGMENT_SIZE >> 1)) {
253             /* preserve current segment; insert this one in front */
254 #ifdef _TRACE_HEAP
255             printf("allocating large segment (%d bytes) on heap %p\n",
256                    bytes, heap);
257 #endif
258             heap_loc = XtMalloc(bytes + (Cardinal) sizeof(char *));
259             if (heap->start) {
260                 *(char **) heap_loc = *(char **) heap->start;
261                 *(char **) heap->start = heap_loc;
262             }
263             else {
264                 *(char **) heap_loc = NULL;
265                 heap->start = heap_loc;
266             }
267             return heap_loc + sizeof(char *);
268         }
269         /* else discard remainder of this segment */
270 #ifdef _TRACE_HEAP
271         printf("allocating new segment on heap %p\n", heap);
272 #endif
273         heap_loc = XtMalloc((unsigned) HEAP_SEGMENT_SIZE);
274         *(char **) heap_loc = heap->start;
275         heap->start = heap_loc;
276         heap->current = heap_loc + sizeof(char *);
277         heap->bytes_remaining = HEAP_SEGMENT_SIZE - sizeof(char *);
278     }
279     bytes = (Cardinal) ((bytes + (sizeof(long) - 1)) & (~(sizeof(long) - 1)));
280     heap_loc = heap->current;
281     heap->current += bytes;
282     heap->bytes_remaining = (heap->bytes_remaining - (int) bytes);      /* can be negative, if rounded */
283     return heap_loc;
284 }
285 
286 void
_XtHeapFree(Heap * heap)287 _XtHeapFree(Heap *heap)
288 {
289     char *segment = heap->start;
290 
291     while (segment != NULL) {
292         char *next_segment = *(char **) segment;
293 
294         XtFree(segment);
295         segment = next_segment;
296     }
297     heap->start = NULL;
298     heap->bytes_remaining = 0;
299 }
300 
301 #else
302 
303 /*
304  * X Toolkit Memory Trace Allocation Routines
305  */
306 
307 #undef XtMalloc
308 #undef XtRealloc
309 #undef XtCalloc
310 #undef XtFree
311 
312 typedef struct _Stats *StatsPtr;
313 typedef struct _Stats {
314     StatsPtr prev, next;
315     const char *file;
316     int line;
317     unsigned size;
318     unsigned long seq;
319     XtPointer heap;
320 } Stats;
321 
322 static StatsPtr XtMemory = (StatsPtr) NULL;
323 static unsigned long ActiveXtMemory = 0;
324 static unsigned long XtSeqId = 0;
325 static unsigned long XtSeqBreakpoint = (unsigned long) (~0UL);
326 
327 #define StatsSize(n) (unsigned)((((n) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) + sizeof(Stats))
328 #define ToStats(ptr) ((StatsPtr)(ptr - sizeof(Stats)))
329 #define ToMem(ptr) (((char *)ptr) + sizeof(Stats))
330 
331 #define CHAIN(ptr,len,hp) \
332     ptr->next = XtMemory; \
333     if (XtMemory) \
334         XtMemory->prev = ptr; \
335     XtMemory = ptr; \
336     ptr->prev = (StatsPtr)NULL; \
337     ptr->file = file; \
338     ptr->line = line; \
339     ptr->size = len; \
340     ptr->heap = hp; \
341     if (file) \
342         ActiveXtMemory += len; \
343     ptr->seq = XtSeqId; \
344     if (XtSeqId == XtSeqBreakpoint) \
345         _XtBreakpoint(ptr); \
346     XtSeqId++
347 
348 /*ARGUSED*/
349 static void
_XtBreakpoint(StatsPtr mem)350 _XtBreakpoint(StatsPtr mem)
351 {
352     mem->seq = XtSeqId;         /* avoid being optimized out of existence */
353 }
354 
355 char *
_XtMalloc(unsigned size,const char * file,int line)356 _XtMalloc(unsigned size, const char *file, int line)
357 {
358     StatsPtr ptr;
359     unsigned newsize;
360     char *retval = NULL;
361 
362     LOCK_PROCESS;
363     newsize = StatsSize(size);
364     if ((ptr = (StatsPtr) Xmalloc(newsize)) == NULL)
365         _XtAllocError("malloc");
366     CHAIN(ptr, size, NULL);
367     retval = (ToMem(ptr));
368     UNLOCK_PROCESS;
369     return retval;
370 }
371 
372 char *
XtMalloc(unsigned size)373 XtMalloc(unsigned size)
374 {
375     return _XtMalloc(size, (char *) NULL, 0);
376 }
377 
378 char *
_XtRealloc(char * ptr,unsigned size,const char * file,int line)379 _XtRealloc(char *ptr, unsigned size, const char *file, int line)
380 {
381     char *newptr;
382 
383     LOCK_PROCESS;
384     newptr = _XtMalloc(size, file, line);
385     if (ptr) {
386         unsigned copysize = ToStats(ptr)->size;
387 
388         if (copysize > size)
389             copysize = size;
390         memmove(newptr, ptr, copysize);
391         _XtFree(ptr);
392     }
393     UNLOCK_PROCESS;
394     return (newptr);
395 }
396 
397 char *
XtRealloc(char * ptr,unsigned size)398 XtRealloc(char *ptr, unsigned size)
399 {
400     return _XtRealloc(ptr, size, (char *) NULL, 0);
401 }
402 
403 char *
_XtCalloc(unsigned num,unsigned size,const char * file,int line)404 _XtCalloc(unsigned num, unsigned size, const char *file, int line)
405 {
406     StatsPtr ptr;
407     unsigned total, newsize;
408     char *retval = NULL;
409 
410     LOCK_PROCESS;
411     total = num * size;
412     newsize = StatsSize(total);
413     if ((ptr = (StatsPtr) Xcalloc(newsize, 1)) == NULL)
414         _XtAllocError("calloc");
415     CHAIN(ptr, total, NULL);
416     retval = (ToMem(ptr));
417     UNLOCK_PROCESS;
418     return retval;
419 }
420 
421 char *
XtCalloc(unsigned num,unsigned size)422 XtCalloc(unsigned num, unsigned size)
423 {
424     return _XtCalloc(num, size, (char *) NULL, 0);
425 }
426 
427 Boolean
_XtIsValidPointer(char * ptr)428 _XtIsValidPointer(char *ptr)
429 {
430     register StatsPtr mem;
431     register StatsPtr stp = ToStats(ptr);
432 
433     LOCK_PROCESS;
434     for (mem = XtMemory; mem; mem = mem->next) {
435         if (mem == stp) {
436             UNLOCK_PROCESS;
437             return True;
438         }
439     }
440     UNLOCK_PROCESS;
441     return False;
442 }
443 
444 Boolean _XtValidateMemory = False;
445 
446 void
_XtFree(char * ptr)447 _XtFree(char *ptr)
448 {
449     register StatsPtr stp;
450 
451     LOCK_PROCESS;
452     if (ptr) {
453         if (_XtValidateMemory && !_XtIsValidPointer(ptr))
454             abort();
455         stp = ToStats(ptr);
456         if (stp->file)
457             ActiveXtMemory -= stp->size;
458         if (stp->prev)
459             stp->prev->next = stp->next;
460         else
461             XtMemory = stp->next;
462         if (stp->next)
463             stp->next->prev = stp->prev;
464         Xfree((char *) stp);
465     }
466     UNLOCK_PROCESS;
467 }
468 
469 void
XtFree(char * ptr)470 XtFree(char *ptr)
471 {
472     _XtFree(ptr);
473 }
474 
475 char *
_XtHeapMalloc(Heap * heap,Cardinal size,const char * file,int line)476 _XtHeapMalloc(Heap *heap, Cardinal size, const char *file, int line)
477 {
478     StatsPtr ptr;
479     unsigned newsize;
480     XtPointer hp = (XtPointer) heap;
481     char *retval = NULL;
482 
483     LOCK_PROCESS;
484     newsize = StatsSize(size);
485     if ((ptr = (StatsPtr) Xmalloc(newsize)) == NULL)
486         _XtAllocError("malloc");
487     CHAIN(ptr, size, hp);
488     retval = (ToMem(ptr));
489     UNLOCK_PROCESS;
490     return retval;
491 }
492 
493 void
_XtHeapFree(Heap * heap)494 _XtHeapFree(Heap *heap)
495 {
496     register StatsPtr mem, next;
497 
498     LOCK_PROCESS;
499     for (mem = XtMemory; mem; mem = next) {
500         next = mem->next;
501         if (mem->heap == heap) {
502             if (mem->file)
503                 ActiveXtMemory -= mem->size;
504             if (mem->prev)
505                 mem->prev->next = next;
506             else
507                 XtMemory = next;
508             if (next)
509                 next->prev = mem->prev;
510             Xfree((char *) mem);
511         }
512     }
513     UNLOCK_PROCESS;
514 }
515 
516 #include <stdio.h>
517 
518 void
_XtPrintMemory(const char * filename)519 _XtPrintMemory(const char *filename)
520 {
521     register StatsPtr mem;
522     FILE *f;
523 
524     if (filename == NULL)
525         f = stderr;
526     else
527         f = fopen(filename, "w");
528     LOCK_PROCESS;
529     fprintf(f, "total size: %lu\n", ActiveXtMemory);
530     for (mem = XtMemory; mem; mem = mem->next) {
531         if (mem->file)
532             fprintf(f, "size: %6d  seq: %5lu  %12s(%4d)  %s\n",
533                     mem->size, mem->seq,
534                     mem->file, mem->line, mem->heap ? "heap" : "");
535     }
536     UNLOCK_PROCESS;
537     if (filename)
538         fclose(f);
539 }
540 
541 #endif                          /* XTTRACEMEMORY */
542