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