1 /* GLIB - Library of useful routines for C programming 2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the 16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 * Boston, MA 02111-1307, USA. 18 */ 19 20 /* 21 * Modified by the GLib Team and others 1997-2000. See the AUTHORS 22 * file for a list of people on the GLib Team. See the ChangeLog 23 * files for a list of changes. These files are distributed with 24 * GLib at ftp://ftp.gtk.org/pub/gtk/. 25 */ 26 27 /* 28 * MT safe 29 */ 30 31 #include "config.h" 32 33 #include <stdlib.h> 34 #include <string.h> 35 #include <signal.h> 36 37 #include "glib.h" 38 #include "gthreadprivate.h" 39 #include "galias.h" 40 41 #define MEM_PROFILE_TABLE_SIZE 4096 42 43 44 /* notes on macros: 45 * having G_DISABLE_CHECKS defined disables use of glib_mem_profiler_table and 46 * g_mem_profile(). 47 * REALLOC_0_WORKS is defined if g_realloc (NULL, x) works. 48 * SANE_MALLOC_PROTOS is defined if the systems malloc() and friends functions 49 * match the corresponding GLib prototypes, keep configure.in and gmem.h in sync here. 50 * g_mem_gc_friendly is TRUE, freed memory should be 0-wiped. 51 */ 52 53 /* --- prototypes --- */ 54 static gboolean g_mem_initialized = FALSE; 55 static void g_mem_init_nomessage (void); 56 57 58 /* --- malloc wrappers --- */ 59 #ifndef REALLOC_0_WORKS 60 static gpointer 61 standard_realloc (gpointer mem, 62 gsize n_bytes) 63 { 64 if (!mem) 65 return malloc (n_bytes); 66 else 67 return realloc (mem, n_bytes); 68 } 69 #endif /* !REALLOC_0_WORKS */ 70 71 #ifdef SANE_MALLOC_PROTOS 72 # define standard_malloc malloc 73 # ifdef REALLOC_0_WORKS 74 # define standard_realloc realloc 75 # endif /* REALLOC_0_WORKS */ 76 # define standard_free free 77 # define standard_calloc calloc 78 # define standard_try_malloc malloc 79 # define standard_try_realloc realloc 80 #else /* !SANE_MALLOC_PROTOS */ 81 static gpointer 82 standard_malloc (gsize n_bytes) 83 { 84 return malloc (n_bytes); 85 } 86 # ifdef REALLOC_0_WORKS 87 static gpointer 88 standard_realloc (gpointer mem, 89 gsize n_bytes) 90 { 91 return realloc (mem, n_bytes); 92 } 93 # endif /* REALLOC_0_WORKS */ 94 static void 95 standard_free (gpointer mem) 96 { 97 free (mem); 98 } 99 static gpointer 100 standard_calloc (gsize n_blocks, 101 gsize n_bytes) 102 { 103 return calloc (n_blocks, n_bytes); 104 } 105 #define standard_try_malloc standard_malloc 106 #define standard_try_realloc standard_realloc 107 #endif /* !SANE_MALLOC_PROTOS */ 108 109 110 /* --- variables --- */ 111 static GMemVTable glib_mem_vtable = { 112 standard_malloc, 113 standard_realloc, 114 standard_free, 115 standard_calloc, 116 standard_try_malloc, 117 standard_try_realloc, 118 }; 119 120 121 /* --- functions --- */ 122 gpointer 123 g_malloc (gsize n_bytes) 124 { 125 if (G_UNLIKELY (!g_mem_initialized)) 126 g_mem_init_nomessage(); 127 if (G_LIKELY (n_bytes)) 128 { 129 gpointer mem; 130 131 mem = glib_mem_vtable.malloc (n_bytes); 132 if (mem) 133 return mem; 134 135 g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes", 136 G_STRLOC, n_bytes); 137 } 138 139 return NULL; 140 } 141 142 gpointer 143 g_malloc0 (gsize n_bytes) 144 { 145 if (G_UNLIKELY (!g_mem_initialized)) 146 g_mem_init_nomessage(); 147 if (G_LIKELY (n_bytes)) 148 { 149 gpointer mem; 150 151 mem = glib_mem_vtable.calloc (1, n_bytes); 152 if (mem) 153 return mem; 154 155 g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes", 156 G_STRLOC, n_bytes); 157 } 158 159 return NULL; 160 } 161 162 gpointer 163 g_realloc (gpointer mem, 164 gsize n_bytes) 165 { 166 if (G_UNLIKELY (!g_mem_initialized)) 167 g_mem_init_nomessage(); 168 if (G_LIKELY (n_bytes)) 169 { 170 mem = glib_mem_vtable.realloc (mem, n_bytes); 171 if (mem) 172 return mem; 173 174 g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes", 175 G_STRLOC, n_bytes); 176 } 177 178 if (mem) 179 glib_mem_vtable.free (mem); 180 181 return NULL; 182 } 183 184 void 185 g_free (gpointer mem) 186 { 187 if (G_UNLIKELY (!g_mem_initialized)) 188 g_mem_init_nomessage(); 189 if (G_LIKELY (mem)) 190 glib_mem_vtable.free (mem); 191 } 192 193 gpointer 194 g_try_malloc (gsize n_bytes) 195 { 196 if (G_UNLIKELY (!g_mem_initialized)) 197 g_mem_init_nomessage(); 198 if (G_LIKELY (n_bytes)) 199 return glib_mem_vtable.try_malloc (n_bytes); 200 else 201 return NULL; 202 } 203 204 gpointer 205 g_try_malloc0 (gsize n_bytes) 206 { 207 gpointer mem; 208 209 mem = g_try_malloc (n_bytes); 210 211 if (mem) 212 memset (mem, 0, n_bytes); 213 214 return mem; 215 } 216 217 gpointer 218 g_try_realloc (gpointer mem, 219 gsize n_bytes) 220 { 221 if (G_UNLIKELY (!g_mem_initialized)) 222 g_mem_init_nomessage(); 223 if (G_LIKELY (n_bytes)) 224 return glib_mem_vtable.try_realloc (mem, n_bytes); 225 226 if (mem) 227 glib_mem_vtable.free (mem); 228 229 return NULL; 230 } 231 232 static gpointer 233 fallback_calloc (gsize n_blocks, 234 gsize n_block_bytes) 235 { 236 gsize l = n_blocks * n_block_bytes; 237 gpointer mem = glib_mem_vtable.malloc (l); 238 239 if (mem) 240 memset (mem, 0, l); 241 242 return mem; 243 } 244 245 static gboolean vtable_set = FALSE; 246 247 /** 248 * g_mem_is_system_malloc 249 * 250 * Checks whether the allocator used by g_malloc() is the system's 251 * malloc implementation. If it returns %TRUE memory allocated with 252 * malloc() can be used interchangeable with memory allocated using g_malloc(). 253 * This function is useful for avoiding an extra copy of allocated memory returned 254 * by a non-GLib-based API. 255 * 256 * A different allocator can be set using g_mem_set_vtable(). 257 * 258 * Return value: if %TRUE, malloc() and g_malloc() can be mixed. 259 **/ 260 gboolean 261 g_mem_is_system_malloc (void) 262 { 263 return !vtable_set; 264 } 265 266 void 267 g_mem_set_vtable (GMemVTable *vtable) 268 { 269 if (!vtable_set) 270 { 271 if (vtable->malloc && vtable->realloc && vtable->free) 272 { 273 glib_mem_vtable.malloc = vtable->malloc; 274 glib_mem_vtable.realloc = vtable->realloc; 275 glib_mem_vtable.free = vtable->free; 276 glib_mem_vtable.calloc = vtable->calloc ? vtable->calloc : fallback_calloc; 277 glib_mem_vtable.try_malloc = vtable->try_malloc ? vtable->try_malloc : glib_mem_vtable.malloc; 278 glib_mem_vtable.try_realloc = vtable->try_realloc ? vtable->try_realloc : glib_mem_vtable.realloc; 279 vtable_set = TRUE; 280 } 281 else 282 g_warning (G_STRLOC ": memory allocation vtable lacks one of malloc(), realloc() or free()"); 283 } 284 else 285 g_warning (G_STRLOC ": memory allocation vtable can only be set once at startup"); 286 } 287 288 289 /* --- memory profiling and checking --- */ 290 #ifdef G_DISABLE_CHECKS 291 GMemVTable *glib_mem_profiler_table = &glib_mem_vtable; 292 void 293 g_mem_profile (void) 294 { 295 } 296 #else /* !G_DISABLE_CHECKS */ 297 typedef enum { 298 PROFILER_FREE = 0, 299 PROFILER_ALLOC = 1, 300 PROFILER_RELOC = 2, 301 PROFILER_ZINIT = 4 302 } ProfilerJob; 303 static guint *profile_data = NULL; 304 static gsize profile_allocs = 0; 305 static gsize profile_zinit = 0; 306 static gsize profile_frees = 0; 307 static GMutex *gmem_profile_mutex = NULL; 308 #ifdef G_ENABLE_DEBUG 309 static volatile gsize g_trap_free_size = 0; 310 static volatile gsize g_trap_realloc_size = 0; 311 static volatile gsize g_trap_malloc_size = 0; 312 #endif /* G_ENABLE_DEBUG */ 313 314 #define PROFILE_TABLE(f1,f2,f3) ( ( ((f3) << 2) | ((f2) << 1) | (f1) ) * (MEM_PROFILE_TABLE_SIZE + 1)) 315 316 static void 317 profiler_log (ProfilerJob job, 318 gsize n_bytes, 319 gboolean success) 320 { 321 g_mutex_lock (gmem_profile_mutex); 322 if (!profile_data) 323 { 324 profile_data = standard_calloc ((MEM_PROFILE_TABLE_SIZE + 1) * 8, 325 sizeof (profile_data[0])); 326 if (!profile_data) /* memory system kiddin' me, eh? */ 327 { 328 g_mutex_unlock (gmem_profile_mutex); 329 return; 330 } 331 } 332 333 if (n_bytes < MEM_PROFILE_TABLE_SIZE) 334 profile_data[n_bytes + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0, 335 (job & PROFILER_RELOC) != 0, 336 success != 0)] += 1; 337 else 338 profile_data[MEM_PROFILE_TABLE_SIZE + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0, 339 (job & PROFILER_RELOC) != 0, 340 success != 0)] += 1; 341 if (success) 342 { 343 if (job & PROFILER_ALLOC) 344 { 345 profile_allocs += n_bytes; 346 if (job & PROFILER_ZINIT) 347 profile_zinit += n_bytes; 348 } 349 else 350 profile_frees += n_bytes; 351 } 352 g_mutex_unlock (gmem_profile_mutex); 353 } 354 355 static void 356 profile_print_locked (guint *local_data, 357 gboolean success) 358 { 359 gboolean need_header = TRUE; 360 guint i; 361 362 for (i = 0; i <= MEM_PROFILE_TABLE_SIZE; i++) 363 { 364 glong t_malloc = local_data[i + PROFILE_TABLE (1, 0, success)]; 365 glong t_realloc = local_data[i + PROFILE_TABLE (1, 1, success)]; 366 glong t_free = local_data[i + PROFILE_TABLE (0, 0, success)]; 367 glong t_refree = local_data[i + PROFILE_TABLE (0, 1, success)]; 368 369 if (!t_malloc && !t_realloc && !t_free && !t_refree) 370 continue; 371 else if (need_header) 372 { 373 need_header = FALSE; 374 g_print (" blocks of | allocated | freed | allocated | freed | n_bytes \n"); 375 g_print (" n_bytes | n_times by | n_times by | n_times by | n_times by | remaining \n"); 376 g_print (" | malloc() | free() | realloc() | realloc() | \n"); 377 g_print ("===========|============|============|============|============|===========\n"); 378 } 379 if (i < MEM_PROFILE_TABLE_SIZE) 380 g_print ("%10u | %10ld | %10ld | %10ld | %10ld |%+11ld\n", 381 i, t_malloc, t_free, t_realloc, t_refree, 382 (t_malloc - t_free + t_realloc - t_refree) * i); 383 else if (i >= MEM_PROFILE_TABLE_SIZE) 384 g_print (" >%6u | %10ld | %10ld | %10ld | %10ld | ***\n", 385 i, t_malloc, t_free, t_realloc, t_refree); 386 } 387 if (need_header) 388 g_print (" --- none ---\n"); 389 } 390 391 void 392 g_mem_profile (void) 393 { 394 guint local_data[(MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])]; 395 gsize local_allocs; 396 gsize local_zinit; 397 gsize local_frees; 398 399 if (G_UNLIKELY (!g_mem_initialized)) 400 g_mem_init_nomessage(); 401 402 g_mutex_lock (gmem_profile_mutex); 403 404 local_allocs = profile_allocs; 405 local_zinit = profile_zinit; 406 local_frees = profile_frees; 407 408 if (!profile_data) 409 { 410 g_mutex_unlock (gmem_profile_mutex); 411 return; 412 } 413 414 memcpy (local_data, profile_data, 415 (MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])); 416 417 g_mutex_unlock (gmem_profile_mutex); 418 419 g_print ("GLib Memory statistics (successful operations):\n"); 420 profile_print_locked (local_data, TRUE); 421 g_print ("GLib Memory statistics (failing operations):\n"); 422 profile_print_locked (local_data, FALSE); 423 g_print ("Total bytes: allocated=%"G_GSIZE_FORMAT", " 424 "zero-initialized=%"G_GSIZE_FORMAT" (%.2f%%), " 425 "freed=%"G_GSIZE_FORMAT" (%.2f%%), " 426 "remaining=%"G_GSIZE_FORMAT"\n", 427 local_allocs, 428 local_zinit, 429 ((gdouble) local_zinit) / local_allocs * 100.0, 430 local_frees, 431 ((gdouble) local_frees) / local_allocs * 100.0, 432 local_allocs - local_frees); 433 } 434 435 static gpointer 436 profiler_try_malloc (gsize n_bytes) 437 { 438 gsize *p; 439 440 #ifdef G_ENABLE_DEBUG 441 if (g_trap_malloc_size == n_bytes) 442 G_BREAKPOINT (); 443 #endif /* G_ENABLE_DEBUG */ 444 445 p = standard_malloc (sizeof (gsize) * 2 + n_bytes); 446 447 if (p) 448 { 449 p[0] = 0; /* free count */ 450 p[1] = n_bytes; /* length */ 451 profiler_log (PROFILER_ALLOC, n_bytes, TRUE); 452 p += 2; 453 } 454 else 455 profiler_log (PROFILER_ALLOC, n_bytes, FALSE); 456 457 return p; 458 } 459 460 static gpointer 461 profiler_malloc (gsize n_bytes) 462 { 463 gpointer mem = profiler_try_malloc (n_bytes); 464 465 if (!mem) 466 g_mem_profile (); 467 468 return mem; 469 } 470 471 static gpointer 472 profiler_calloc (gsize n_blocks, 473 gsize n_block_bytes) 474 { 475 gsize l = n_blocks * n_block_bytes; 476 gsize *p; 477 478 #ifdef G_ENABLE_DEBUG 479 if (g_trap_malloc_size == l) 480 G_BREAKPOINT (); 481 #endif /* G_ENABLE_DEBUG */ 482 483 p = standard_calloc (1, sizeof (gsize) * 2 + l); 484 485 if (p) 486 { 487 p[0] = 0; /* free count */ 488 p[1] = l; /* length */ 489 profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, TRUE); 490 p += 2; 491 } 492 else 493 { 494 profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, FALSE); 495 g_mem_profile (); 496 } 497 498 return p; 499 } 500 501 static void 502 profiler_free (gpointer mem) 503 { 504 gsize *p = mem; 505 506 p -= 2; 507 if (p[0]) /* free count */ 508 { 509 g_warning ("free(%p): memory has been freed %"G_GSIZE_FORMAT" times already", 510 p + 2, p[0]); 511 profiler_log (PROFILER_FREE, 512 p[1], /* length */ 513 FALSE); 514 } 515 else 516 { 517 #ifdef G_ENABLE_DEBUG 518 if (g_trap_free_size == p[1]) 519 G_BREAKPOINT (); 520 #endif /* G_ENABLE_DEBUG */ 521 522 profiler_log (PROFILER_FREE, 523 p[1], /* length */ 524 TRUE); 525 memset (p + 2, 0xaa, p[1]); 526 527 /* for all those that miss standard_free (p); in this place, yes, 528 * we do leak all memory when profiling, and that is intentional 529 * to catch double frees. patch submissions are futile. 530 */ 531 } 532 p[0] += 1; 533 } 534 535 static gpointer 536 profiler_try_realloc (gpointer mem, 537 gsize n_bytes) 538 { 539 gsize *p = mem; 540 541 p -= 2; 542 543 #ifdef G_ENABLE_DEBUG 544 if (g_trap_realloc_size == n_bytes) 545 G_BREAKPOINT (); 546 #endif /* G_ENABLE_DEBUG */ 547 548 if (mem && p[0]) /* free count */ 549 { 550 g_warning ("realloc(%p, %"G_GSIZE_FORMAT"): " 551 "memory has been freed %"G_GSIZE_FORMAT" times already", 552 p + 2, (gsize) n_bytes, p[0]); 553 profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE); 554 555 return NULL; 556 } 557 else 558 { 559 p = standard_realloc (mem ? p : NULL, sizeof (gsize) * 2 + n_bytes); 560 561 if (p) 562 { 563 if (mem) 564 profiler_log (PROFILER_FREE | PROFILER_RELOC, p[1], TRUE); 565 p[0] = 0; 566 p[1] = n_bytes; 567 profiler_log (PROFILER_ALLOC | PROFILER_RELOC, p[1], TRUE); 568 p += 2; 569 } 570 else 571 profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE); 572 573 return p; 574 } 575 } 576 577 static gpointer 578 profiler_realloc (gpointer mem, 579 gsize n_bytes) 580 { 581 mem = profiler_try_realloc (mem, n_bytes); 582 583 if (!mem) 584 g_mem_profile (); 585 586 return mem; 587 } 588 589 static GMemVTable profiler_table = { 590 profiler_malloc, 591 profiler_realloc, 592 profiler_free, 593 profiler_calloc, 594 profiler_try_malloc, 595 profiler_try_realloc, 596 }; 597 GMemVTable *glib_mem_profiler_table = &profiler_table; 598 599 #endif /* !G_DISABLE_CHECKS */ 600 601 /* --- MemChunks --- */ 602 #ifndef G_ALLOC_AND_FREE 603 typedef struct _GAllocator GAllocator; 604 typedef struct _GMemChunk GMemChunk; 605 #define G_ALLOC_ONLY 1 606 #define G_ALLOC_AND_FREE 2 607 #endif 608 609 struct _GMemChunk { 610 guint alloc_size; /* the size of an atom */ 611 }; 612 613 GMemChunk* 614 g_mem_chunk_new (const gchar *name, 615 gint atom_size, 616 gsize area_size, 617 gint type) 618 { 619 GMemChunk *mem_chunk; 620 g_return_val_if_fail (atom_size > 0, NULL); 621 622 mem_chunk = g_slice_new (GMemChunk); 623 mem_chunk->alloc_size = atom_size; 624 return mem_chunk; 625 } 626 627 void 628 g_mem_chunk_destroy (GMemChunk *mem_chunk) 629 { 630 g_return_if_fail (mem_chunk != NULL); 631 632 g_slice_free (GMemChunk, mem_chunk); 633 } 634 635 gpointer 636 g_mem_chunk_alloc (GMemChunk *mem_chunk) 637 { 638 g_return_val_if_fail (mem_chunk != NULL, NULL); 639 640 return g_slice_alloc (mem_chunk->alloc_size); 641 } 642 643 gpointer 644 g_mem_chunk_alloc0 (GMemChunk *mem_chunk) 645 { 646 g_return_val_if_fail (mem_chunk != NULL, NULL); 647 648 return g_slice_alloc0 (mem_chunk->alloc_size); 649 } 650 651 void 652 g_mem_chunk_free (GMemChunk *mem_chunk, 653 gpointer mem) 654 { 655 g_return_if_fail (mem_chunk != NULL); 656 657 g_slice_free1 (mem_chunk->alloc_size, mem); 658 } 659 660 void g_mem_chunk_clean (GMemChunk *mem_chunk) {} 661 void g_mem_chunk_reset (GMemChunk *mem_chunk) {} 662 void g_mem_chunk_print (GMemChunk *mem_chunk) {} 663 void g_mem_chunk_info (void) {} 664 void g_blow_chunks (void) {} 665 666 GAllocator* 667 g_allocator_new (const gchar *name, 668 guint n_preallocs) 669 { 670 static struct _GAllocator { 671 gchar *name; 672 guint16 n_preallocs; 673 guint is_unused : 1; 674 guint type : 4; 675 GAllocator *last; 676 GMemChunk *mem_chunk; 677 gpointer free_list; 678 } dummy = { 679 "GAllocator is deprecated", 1, TRUE, 0, NULL, NULL, NULL, 680 }; 681 /* some (broken) GAllocator uses depend on non-NULL allocators */ 682 return (void*) &dummy; 683 } 684 685 void 686 g_allocator_free (GAllocator *allocator) 687 { 688 } 689 690 #ifdef ENABLE_GC_FRIENDLY_DEFAULT 691 gboolean g_mem_gc_friendly = TRUE; 692 #else 693 gboolean g_mem_gc_friendly = FALSE; 694 #endif 695 696 static void 697 g_mem_init_nomessage (void) 698 { 699 gchar buffer[1024]; 700 const gchar *val; 701 const GDebugKey keys[] = { 702 { "gc-friendly", 1 }, 703 }; 704 gint flags; 705 if (g_mem_initialized) 706 return; 707 /* don't use g_malloc/g_message here */ 708 val = _g_getenv_nomalloc ("G_DEBUG", buffer); 709 flags = !val ? 0 : g_parse_debug_string (val, keys, G_N_ELEMENTS (keys)); 710 if (flags & 1) /* gc-friendly */ 711 { 712 g_mem_gc_friendly = TRUE; 713 } 714 g_mem_initialized = TRUE; 715 } 716 717 void 718 _g_mem_thread_init_noprivate_nomessage (void) 719 { 720 /* we may only create mutexes here, locking/ 721 * unlocking a mutex does not yet work. 722 */ 723 g_mem_init_nomessage(); 724 #ifndef G_DISABLE_CHECKS 725 gmem_profile_mutex = g_mutex_new (); 726 #endif 727 } 728 729 #define __G_MEM_C__ 730 #include "galiasdef.c" 731