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