From 9f529d7cfac3afacf602f9f04d8544dbacc33962 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Fri, 31 Jan 2014 23:28:38 -0200 Subject: [PATCH] [BZ #12751] * manual/memory.texi: Document MTASC-safety properties. --- ChangeLog | 5 + NEWS | 2 +- manual/memory.texi | 533 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 539 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 0b7a976..bcc89c4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2014-01-31 Alexandre Oliva + [BZ #12751] + * manual/memory.texi: Document MTASC-safety properties. + +2014-01-31 Alexandre Oliva + * manual/math.texi: Document MTASC-safety properties. 2014-01-31 Alexandre Oliva diff --git a/NEWS b/NEWS index 1d321b3..7998c75 100644 --- a/NEWS +++ b/NEWS @@ -10,7 +10,7 @@ Version 2.19 * The following bugs are resolved with this release: 156, 387, 431, 762, 832, 926, 2801, 4772, 6786, 6787, 6807, 6810, 7003, - 9721, 9954, 10253, 10278, 11087, 11157, 11214, 12100, 12486, 12986, + 9721, 9954, 10253, 10278, 11087, 11157, 11214, 12100, 12486, 12751, 12986, 13028, 13982, 13985, 14029, 14032, 14120, 14143, 14155, 14286, 14547, 14699, 14752, 14782, 14876, 14910, 15004, 15048, 15073, 15089, 15128, 15218, 15268, 15277, 15308, 15362, 15374, 15400, 15425, 15427, 15483, diff --git a/manual/memory.texi b/manual/memory.texi index 55a6a50..4beb322 100644 --- a/manual/memory.texi +++ b/manual/memory.texi @@ -302,6 +302,245 @@ this function is in @file{stdlib.h}. @comment malloc.h stdlib.h @comment ISO @deftypefun {void *} malloc (size_t @var{size}) +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{} @acsmem{}}} +@c Malloc hooks and __morecore pointers, as well as such parameters as +@c max_n_mmaps and max_mmapped_mem, are accessed without guards, so they +@c could pose a thread safety issue; in order to not declare malloc +@c MT-unsafe, it's modifying the hooks and parameters while multiple +@c threads are active that is regarded as unsafe. An arena's next field +@c is initialized and never changed again, except for main_arena's, +@c that's protected by list_lock; next_free is only modified while +@c list_lock is held too. All other data members of an arena, as well +@c as the metadata of the memory areas assigned to it, are only modified +@c while holding the arena's mutex (fastbin pointers use catomic ops +@c because they may be modified by free without taking the arena's +@c lock). Some reassurance was needed for fastbins, for it wasn't clear +@c how they were initialized. It turns out they are always +@c zero-initialized: main_arena's, for being static data, and other +@c arena's, for being just-mmapped memory. + +@c Leaking file descriptors and memory in case of cancellation is +@c unavoidable without disabling cancellation, but the lock situation is +@c a bit more complicated: we don't have fallback arenas for malloc to +@c be safe to call from within signal handlers. Error-checking mutexes +@c or trylock could enable us to try and use alternate arenas, even with +@c -DPER_THREAD (enabled by default), but supporting interruption +@c (cancellation or signal handling) while holding the arena list mutex +@c would require more work; maybe blocking signals and disabling async +@c cancellation while manipulating the arena lists? + +@c __libc_malloc @asulock @aculock @acsfd @acsmem +@c force_reg ok +@c *malloc_hook unguarded +@c arena_lookup ok +@c tsd_getspecific ok, TLS +@c arena_lock @asulock @aculock @acsfd @acsmem +@c mutex_lock @asulock @aculock +@c arena_get2 @asulock @aculock @acsfd @acsmem +@c get_free_list @asulock @aculock +@c mutex_lock (list_lock) dup @asulock @aculock +@c mutex_unlock (list_lock) dup @aculock +@c mutex_lock (arena lock) dup @asulock @aculock [returns locked] +@c tsd_setspecific ok, TLS +@c __get_nprocs ext ok @acsfd +@c NARENAS_FROM_NCORES ok +@c catomic_compare_and_exchange_bool_acq ok +@c _int_new_arena ok @asulock @aculock @acsmem +@c new_heap ok @acsmem +@c mmap ok @acsmem +@c munmap ok @acsmem +@c mprotect ok +@c chunk2mem ok +@c set_head ok +@c tsd_setspecific dup ok +@c mutex_init ok +@c mutex_lock (just-created mutex) ok, returns locked +@c mutex_lock (list_lock) dup @asulock @aculock +@c atomic_write_barrier ok +@c mutex_unlock (list_lock) @aculock +@c catomic_decrement ok +@c reused_arena @asulock @aculock +@c reads&writes next_to_use and iterates over arena next without guards +@c those are harmless as long as we don't drop arenas from the +@c NEXT list, and we never do; when a thread terminates, +@c arena_thread_freeres prepends the arena to the free_list +@c NEXT_FREE list, but NEXT is never modified, so it's safe! +@c mutex_trylock (arena lock) @asulock @aculock +@c mutex_lock (arena lock) dup @asulock @aculock +@c tsd_setspecific dup ok +@c _int_malloc @acsfd @acsmem +@c checked_request2size ok +@c REQUEST_OUT_OF_RANGE ok +@c request2size ok +@c get_max_fast ok +@c fastbin_index ok +@c fastbin ok +@c catomic_compare_and_exhange_val_acq ok +@c malloc_printerr dup @mtsenv +@c if we get to it, we're toast already, undefined behavior must have +@c been invoked before +@c libc_message @mtsenv [no leaks with cancellation disabled] +@c FATAL_PREPARE ok +@c pthread_setcancelstate disable ok +@c libc_secure_getenv @mtsenv +@c getenv @mtsenv +@c open_not_cancel_2 dup @acsfd +@c strchrnul ok +@c WRITEV_FOR_FATAL ok +@c writev ok +@c mmap ok @acsmem +@c munmap ok @acsmem +@c BEFORE_ABORT @acsfd +@c backtrace ok +@c write_not_cancel dup ok +@c backtrace_symbols_fd @aculock +@c open_not_cancel_2 dup @acsfd +@c read_not_cancel dup ok +@c close_not_cancel_no_status dup @acsfd +@c abort ok +@c itoa_word ok +@c abort ok +@c check_remalloced_chunk ok/disabled +@c chunk2mem dup ok +@c alloc_perturb ok +@c in_smallbin_range ok +@c smallbin_index ok +@c bin_at ok +@c last ok +@c malloc_consolidate ok +@c get_max_fast dup ok +@c clear_fastchunks ok +@c unsorted_chunks dup ok +@c fastbin dup ok +@c atomic_exchange_acq ok +@c check_inuse_chunk dup ok/disabled +@c chunk_at_offset dup ok +@c chunksize dup ok +@c inuse_bit_at_offset dup ok +@c unlink dup ok +@c clear_inuse_bit_at_offset dup ok +@c in_smallbin_range dup ok +@c set_head dup ok +@c malloc_init_state ok +@c bin_at dup ok +@c set_noncontiguous dup ok +@c set_max_fast dup ok +@c initial_top ok +@c unsorted_chunks dup ok +@c check_malloc_state ok/disabled +@c set_inuse_bit_at_offset ok +@c check_malloced_chunk ok/disabled +@c largebin_index ok +@c have_fastchunks ok +@c unsorted_chunks ok +@c bin_at ok +@c chunksize ok +@c chunk_at_offset ok +@c set_head ok +@c set_foot ok +@c mark_bin ok +@c idx2bit ok +@c first ok +@c unlink ok +@c malloc_printerr dup ok +@c in_smallbin_range dup ok +@c idx2block ok +@c idx2bit dup ok +@c next_bin ok +@c sysmalloc @acsfd @acsmem +@c MMAP @acsmem +@c set_head dup ok +@c check_chunk ok/disabled +@c chunk2mem dup ok +@c chunksize dup ok +@c chunk_at_offset dup ok +@c heap_for_ptr ok +@c grow_heap ok +@c mprotect ok +@c set_head dup ok +@c new_heap @acsmem +@c MMAP dup @acsmem +@c munmap @acsmem +@c top ok +@c set_foot dup ok +@c contiguous ok +@c MORECORE ok +@c *__morecore ok unguarded +@c __default_morecore +@c sbrk ok +@c force_reg dup ok +@c *__after_morecore_hook unguarded +@c set_noncontiguous ok +@c malloc_printerr dup ok +@c _int_free (have_lock) @acsfd @acsmem [@asulock @aculock] +@c chunksize dup ok +@c mutex_unlock dup @aculock/!have_lock +@c malloc_printerr dup ok +@c check_inuse_chunk ok/disabled +@c chunk_at_offset dup ok +@c mutex_lock dup @asulock @aculock/@have_lock +@c chunk2mem dup ok +@c free_perturb ok +@c set_fastchunks ok +@c catomic_and ok +@c fastbin_index dup ok +@c fastbin dup ok +@c catomic_compare_and_exchange_val_rel ok +@c chunk_is_mmapped ok +@c contiguous dup ok +@c prev_inuse ok +@c unlink dup ok +@c inuse_bit_at_offset dup ok +@c clear_inuse_bit_at_offset ok +@c unsorted_chunks dup ok +@c in_smallbin_range dup ok +@c set_head dup ok +@c set_foot dup ok +@c check_free_chunk ok/disabled +@c check_chunk dup ok/disabled +@c have_fastchunks dup ok +@c malloc_consolidate dup ok +@c systrim ok +@c MORECORE dup ok +@c *__after_morecore_hook dup unguarded +@c set_head dup ok +@c check_malloc_state ok/disabled +@c top dup ok +@c heap_for_ptr dup ok +@c heap_trim @acsfd @acsmem +@c top dup ok +@c chunk_at_offset dup ok +@c prev_chunk ok +@c chunksize dup ok +@c prev_inuse dup ok +@c delete_heap @acsmem +@c munmap dup @acsmem +@c unlink dup ok +@c set_head dup ok +@c shrink_heap @acsfd +@c check_may_shrink_heap @acsfd +@c open_not_cancel_2 @acsfd +@c read_not_cancel ok +@c close_not_cancel_no_status @acsfd +@c MMAP dup ok +@c madvise ok +@c munmap_chunk @acsmem +@c chunksize dup ok +@c chunk_is_mmapped dup ok +@c chunk2mem dup ok +@c malloc_printerr dup ok +@c munmap dup @acsmem +@c check_malloc_state ok/disabled +@c arena_get_retry @asulock @aculock @acsfd @acsmem +@c mutex_unlock dup @aculock +@c mutex_lock dup @asulock @aculock +@c arena_get2 dup @asulock @aculock @acsfd @acsmem +@c mutex_unlock @aculock +@c mem2chunk ok +@c chunk_is_mmapped ok +@c arena_for_chunk ok +@c chunk_non_main_arena ok +@c heap_for_ptr ok This function returns a pointer to a newly allocated block @var{size} bytes long, or a null pointer if the block could not be allocated. @end deftypefun @@ -407,6 +646,21 @@ The prototype for this function is in @file{stdlib.h}. @comment malloc.h stdlib.h @comment ISO @deftypefun void free (void *@var{ptr}) +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{} @acsmem{}}} +@c __libc_free @asulock @aculock @acsfd @acsmem +@c releasing memory into fastbins modifies the arena without taking +@c its mutex, but catomic operations ensure safety. If two (or more) +@c threads are running malloc and have their own arenas locked when +@c each gets a signal whose handler free()s large (non-fastbin-able) +@c blocks from each other's arena, we deadlock; this is a more general +@c case of @asulock. +@c *__free_hook unguarded +@c mem2chunk ok +@c chunk_is_mmapped ok, chunk bits not modified after allocation +@c chunksize ok +@c munmap_chunk dup @acsmem +@c arena_for_chunk dup ok +@c _int_free (!have_lock) dup @asulock @aculock @acsfd @acsmem The @code{free} function deallocates the block of memory pointed at by @var{ptr}. @end deftypefun @@ -414,6 +668,8 @@ by @var{ptr}. @comment stdlib.h @comment Sun @deftypefun void cfree (void *@var{ptr}) +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{} @acsmem{}}} +@c alias to free This function does the same thing as @code{free}. It's provided for backward compatibility with SunOS; you should use @code{free} instead. @end deftypefun @@ -471,6 +727,48 @@ is declared in @file{stdlib.h}. @comment malloc.h stdlib.h @comment ISO @deftypefun {void *} realloc (void *@var{ptr}, size_t @var{newsize}) +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{} @acsmem{}}} +@c It may call the implementations of malloc and free, so all of their +@c issues arise, plus the realloc hook, also accessed without guards. + +@c __libc_realloc @asulock @aculock @acsfd @acsmem +@c *__realloc_hook unguarded +@c __libc_free dup @asulock @aculock @acsfd @acsmem +@c __libc_malloc dup @asulock @aculock @acsfd @acsmem +@c mem2chunk dup ok +@c chunksize dup ok +@c malloc_printerr dup ok +@c checked_request2size dup ok +@c chunk_is_mmapped dup ok +@c mremap_chunk +@c chunksize dup ok +@c __mremap ok +@c set_head dup ok +@c MALLOC_COPY ok +@c memcpy ok +@c munmap_chunk dup @acsmem +@c arena_for_chunk dup ok +@c mutex_lock (arena mutex) dup @asulock @aculock +@c _int_realloc @acsfd @acsmem +@c malloc_printerr dup ok +@c check_inuse_chunk dup ok/disabled +@c chunk_at_offset dup ok +@c chunksize dup ok +@c set_head_size dup ok +@c chunk_at_offset dup ok +@c set_head dup ok +@c chunk2mem dup ok +@c inuse dup ok +@c unlink dup ok +@c _int_malloc dup @acsfd @acsmem +@c mem2chunk dup ok +@c MALLOC_COPY dup ok +@c _int_free (have_lock) dup @acsfd @acsmem +@c set_inuse_bit_at_offset dup ok +@c set_head dup ok +@c mutex_unlock (arena mutex) dup @aculock +@c _int_free (!have_lock) dup @asulock @aculock @acsfd @acsmem + The @code{realloc} function changes the size of the block whose address is @var{ptr} to be @var{newsize}. @@ -530,6 +828,25 @@ is declared in @file{stdlib.h}. @comment malloc.h stdlib.h @comment ISO @deftypefun {void *} calloc (size_t @var{count}, size_t @var{eltsize}) +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{} @acsmem{}}} +@c Same caveats as malloc. + +@c __libc_calloc @asulock @aculock @acsfd @acsmem +@c *__malloc_hook dup unguarded +@c memset dup ok +@c arena_get @asulock @aculock @acsfd @acsmem +@c arena_lookup dup ok +@c arena_lock dup @asulock @aculock @acsfd @acsmem +@c top dup ok +@c chunksize dup ok +@c heap_for_ptr dup ok +@c _int_malloc dup @acsfd @acsmem +@c arena_get_retry dup @asulock @aculock @acsfd @acsmem +@c mutex_unlock dup @aculock +@c mem2chunk dup ok +@c chunk_is_mmapped dup ok +@c MALLOC_ZERO ok +@c memset dup ok This function allocates a block long enough to contain a vector of @var{count} elements, each of size @var{eltsize}. Its contents are cleared to zero before @code{calloc} returns. @@ -622,6 +939,8 @@ power of two than that, use @code{aligned_alloc} or @code{posix_memalign}. @comment stdlib.h @deftypefun {void *} aligned_alloc (size_t @var{alignment}, size_t @var{size}) +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{} @acsmem{}}} +@c Alias to memalign. The @code{aligned_alloc} function allocates a block of @var{size} bytes whose address is a multiple of @var{alignment}. The @var{alignment} must be a power of two and @var{size} must be a multiple of @var{alignment}. @@ -645,6 +964,29 @@ portability to modern non-POSIX systems than @code{posix_memalign}. @comment malloc.h @comment BSD @deftypefun {void *} memalign (size_t @var{boundary}, size_t @var{size}) +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{} @acsmem{}}} +@c Same issues as malloc. The padding bytes are safely freed in +@c _int_memalign, with the arena still locked. + +@c __libc_memalign @asulock @aculock @acsfd @acsmem +@c *__memalign_hook dup unguarded +@c __libc_malloc dup @asulock @aculock @acsfd @acsmem +@c arena_get dup @asulock @aculock @acsfd @acsmem +@c _int_memalign @acsfd @acsmem +@c _int_malloc dup @acsfd @acsmem +@c checked_request2size dup ok +@c mem2chunk dup ok +@c chunksize dup ok +@c chunk_is_mmapped dup ok +@c set_head dup ok +@c chunk2mem dup ok +@c set_inuse_bit_at_offset dup ok +@c set_head_size dup ok +@c _int_free (have_lock) dup @acsfd @acsmem +@c chunk_at_offset dup ok +@c check_inuse_chunk dup ok +@c arena_get_retry dup @asulock @aculock @acsfd @acsmem +@c mutex_unlock dup @aculock The @code{memalign} function allocates a block of @var{size} bytes whose address is a multiple of @var{boundary}. The @var{boundary} must be a power of two! The function @code{memalign} works by allocating a @@ -670,6 +1012,10 @@ The @code{memalign} function is obsolete and @code{aligned_alloc} or @comment stdlib.h @comment POSIX @deftypefun int posix_memalign (void **@var{memptr}, size_t @var{alignment}, size_t @var{size}) +@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{} @acsmem{}}} +@c Calls memalign unless the requirements are not met (powerof2 macro is +@c safe given an automatic variable as an argument) or there's a +@c memalign hook (accessed unguarded, but safely). The @code{posix_memalign} function is similar to the @code{memalign} function in that it returns a buffer of @var{size} bytes aligned to a multiple of @var{alignment}. But it adds one requirement to the @@ -698,6 +1044,39 @@ systems that do not support @w{ISO C11}. @comment malloc.h stdlib.h @comment BSD @deftypefun {void *} valloc (size_t @var{size}) +@safety{@prelim{}@mtunsafe{@mtuinit{}}@asunsafe{@asuinit{} @asulock{}}@acunsafe{@acuinit{} @aculock{} @acsfd{} @acsmem{}}} +@c __libc_valloc @mtuinit @asuinit @asulock @aculock @acsfd @acsmem +@c ptmalloc_init (once) @mtsenv @asulock @aculock @acsfd @acsmem +@c _dl_addr @asucorrupt? @aculock +@c __rtld_lock_lock_recursive (dl_load_lock) @asucorrupt? @aculock +@c _dl_find_dso_for_object ok, iterates over dl_ns and its _ns_loaded objs +@c the ok above assumes no partial updates on dl_ns and _ns_loaded +@c that could confuse a _dl_addr call in a signal handler +@c _dl_addr_inside_object ok +@c determine_info ok +@c __rtld_lock_unlock_recursive (dl_load_lock) @aculock +@c thread_atfork @asulock @aculock @acsfd @acsmem +@c __register_atfork @asulock @aculock @acsfd @acsmem +@c lll_lock (__fork_lock) @asulock @aculock +@c fork_handler_alloc @asulock @aculock @acsfd @acsmem +@c calloc dup @asulock @aculock @acsfd @acsmem +@c __linkin_atfork ok +@c catomic_compare_and_exchange_bool_acq ok +@c lll_unlock (__fork_lock) @aculock +@c *_environ @mtsenv +@c next_env_entry ok +@c strcspn dup ok +@c __libc_mallopt dup @mtasuconst:mallopt [setting mp_] +@c __malloc_check_init @mtasuconst:malloc_hooks [setting hooks] +@c *__malloc_initialize_hook unguarded, ok +@c *__memalign_hook dup ok, unguarded +@c arena_get dup @asulock @aculock @acsfd @acsmem +@c _int_valloc @acsfd @acsmem +@c malloc_consolidate dup ok +@c _int_memalign dup @acsfd @acsmem +@c arena_get_retry dup @asulock @aculock @acsfd @acsmem +@c _int_memalign dup @acsfd @acsmem +@c mutex_unlock dup @aculock Using @code{valloc} is like using @code{memalign} and passing the page size as the value of the second argument. It is implemented like this: @@ -725,6 +1104,14 @@ interface, defined in @file{malloc.h}. @pindex malloc.h @deftypefun int mallopt (int @var{param}, int @var{value}) +@safety{@prelim{}@mtunsafe{@mtuinit{} @mtasuconst{:mallopt}}@asunsafe{@asuinit{} @asulock{}}@acunsafe{@acuinit{} @aculock{}}} +@c __libc_mallopt @mtuinit @mtasuconst:mallopt @asuinit @asulock @aculock +@c ptmalloc_init (once) dup @mtsenv @asulock @aculock @acsfd @acsmem +@c mutex_lock (main_arena->mutex) @asulock @aculock +@c malloc_consolidate dup ok +@c set_max_fast ok +@c mutex_unlock dup @aculock + When calling @code{mallopt}, the @var{param} argument specifies the parameter to be set, and @var{value} the new value to be set. Possible choices for @var{param}, as defined in @file{malloc.h}, are: @@ -781,6 +1168,17 @@ declared in @file{mcheck.h}. @comment mcheck.h @comment GNU @deftypefun int mcheck (void (*@var{abortfn}) (enum mcheck_status @var{status})) +@safety{@prelim{}@mtunsafe{@mtasurace{:mcheck} @mtasuconst{:malloc_hooks}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}} +@c The hooks must be set up before malloc is first used, which sort of +@c implies @mtuinit/@asuinit but since the function is a no-op if malloc +@c was already used, that doesn't pose any safety issues. The actual +@c problem is with the hooks, designed for single-threaded +@c fully-synchronous operation: they manage an unguarded linked list of +@c allocated blocks, and get temporarily overwritten before calling the +@c allocation functions recursively while holding the old hooks. There +@c are no guards for thread safety, and inconsistent hooks may be found +@c within signal handlers or left behind in case of cancellation. + Calling @code{mcheck} tells @code{malloc} to perform occasional consistency checks. These will catch things such as writing past the end of a block that was allocated with @code{malloc}. @@ -823,6 +1221,18 @@ must be called before the first such function. @end deftypefun @deftypefun {enum mcheck_status} mprobe (void *@var{pointer}) +@safety{@prelim{}@mtunsafe{@mtasurace{:mcheck} @mtasuconst{:malloc_hooks}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}} +@c The linked list of headers may be modified concurrently by other +@c threads, and it may find a partial update if called from a signal +@c handler. It's mostly read only, so cancelling it might be safe, but +@c it will modify global state that, if cancellation hits at just the +@c right spot, may be left behind inconsistent. This path is only taken +@c if checkhdr finds an inconsistency. If the inconsistency could only +@c occur because of earlier undefined behavior, that wouldn't be an +@c additional safety issue problem, but because of the other concurrency +@c issues in the mcheck hooks, the apparent inconsistency could be the +@c result of mcheck's own internal data race. So, AC-Unsafe it is. + The @code{mprobe} function lets you explicitly check for inconsistencies in a particular allocated block. You must have already called @code{mcheck} at the beginning of the program, to do its occasional @@ -1137,6 +1547,24 @@ space's data segment). @comment malloc.h @comment SVID @deftypefun {struct mallinfo} mallinfo (void) +@safety{@prelim{}@mtunsafe{@mtuinit{} @mtasuconst{:mallopt}}@asunsafe{@asuinit{} @asulock{}}@acunsafe{@acuinit{} @aculock{}}} +@c Accessing mp_.n_mmaps and mp_.max_mmapped_mem, modified with atomics +@c but non-atomically elsewhere, may get us inconsistent results. We +@c mark the statistics as unsafe, rather than the fast-path functions +@c that collect the possibly inconsistent data. + +@c __libc_mallinfo @mtuinit @mtasuconst:mallopt @asuinit @asulock @aculock +@c ptmalloc_init (once) dup @mtsenv @asulock @aculock @acsfd @acsmem +@c mutex_lock dup @asulock @aculock +@c int_mallinfo @mtasuconst:mallopt [mp_ access on main_arena] +@c malloc_consolidate dup ok +@c check_malloc_state dup ok/disabled +@c chunksize dup ok +@c fastbin dupo ok +@c bin_at dup ok +@c last dup ok +@c mutex_unlock @aculock + This function returns information about the current dynamic memory usage in a structure of type @code{struct mallinfo}. @end deftypefun @@ -1235,6 +1663,20 @@ penalties for the program if the debugging mode is not enabled. @comment mcheck.h @comment GNU @deftypefun void mtrace (void) +@safety{@prelim{}@mtunsafe{@mtsenv{} @mtasurace{:mtrace} @mtasuconst{:malloc_hooks} @mtuinit{}}@asunsafe{@asuinit{} @ascuheap{} @asucorrupt{} @asulock{}}@acunsafe{@acuinit{} @acucorrupt{} @aculock{} @acsfd{} @acsmem{}}} +@c Like the mcheck hooks, these are not designed with thread safety in +@c mind, because the hook pointers are temporarily modified without +@c regard to other threads, signals or cancellation. + +@c mtrace @mtuinit @mtasurace:mtrace @mtsenv @asuinit @ascuheap @asucorrupt @acuinit @acucorrupt @aculock @acsfd @acsmem +@c __libc_secure_getenv dup @mtsenv +@c malloc dup @ascuheap @acsmem +@c fopen dup @ascuheap @asulock @aculock @acsmem @acsfd +@c fcntl dup ok +@c setvbuf dup @aculock +@c fprintf dup (on newly-created stream) @aculock +@c __cxa_atexit (once) dup @asulock @aculock @acsmem +@c free dup @ascuheap @acsmem When the @code{mtrace} function is called it looks for an environment variable named @code{MALLOC_TRACE}. This variable is supposed to contain a valid file name. The user must have write access. If the @@ -1258,6 +1700,11 @@ systems. The prototype can be found in @file{mcheck.h}. @comment mcheck.h @comment GNU @deftypefun void muntrace (void) +@safety{@prelim{}@mtunsafe{@mtasurace{:mtrace} @mtasuconst{:malloc_hooks} @mtslocale{}}@asunsafe{@asucorrupt{} @ascuheap{}}@acunsafe{@acucorrupt{} @acsmem{} @aculock{} @acsfd{}}} + +@c muntrace @mtasurace:mtrace @mtslocale @asucorrupt @ascuheap @acucorrupt @acsmem @aculock @acsfd +@c fprintf (fputs) dup @mtslocale @asucorrupt @ascuheap @acsmem @aculock @acucorrupt +@c fclose dup @ascuheap @asulock @aculock @acsmem @acsfd The @code{muntrace} function can be called after @code{mtrace} was used to enable tracing the @code{malloc} calls. If no (successful) call of @code{mtrace} was made @code{muntrace} does nothing. @@ -1569,6 +2016,20 @@ as an obstack, it must initialize the obstack by calling @comment obstack.h @comment GNU @deftypefun int obstack_init (struct obstack *@var{obstack-ptr}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acsafe{@acsmem{}}} +@c obstack_init @mtsrace:obstack-ptr @acsmem +@c _obstack_begin @acsmem +@c chunkfun = obstack_chunk_alloc (suggested malloc) +@c freefun = obstack_chunk_free (suggested free) +@c *chunkfun @acsmem +@c obstack_chunk_alloc user-supplied +@c *obstack_alloc_failed_handler user-supplied +@c -> print_and_abort (default) +@c +@c print_and_abort +@c _ dup @ascuintl +@c fxprintf dup @asucorrupt @aculock @acucorrupt +@c exit @acucorrupt? Initialize obstack @var{obstack-ptr} for allocation of objects. This function calls the obstack's @code{obstack_chunk_alloc} function. If allocation of memory fails, the function pointed to by @@ -1624,6 +2085,10 @@ The most direct way to allocate an object in an obstack is with @comment obstack.h @comment GNU @deftypefun {void *} obstack_alloc (struct obstack *@var{obstack-ptr}, int @var{size}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acunsafe{@acucorrupt{} @acsmem{}}} +@c obstack_alloc @mtsrace:obstack-ptr @acucorrupt @acsmem +@c obstack_blank dup @mtsrace:obstack-ptr @acucorrupt @acsmem +@c obstack_finish dup @mtsrace:obstack-ptr @acucorrupt This allocates an uninitialized block of @var{size} bytes in an obstack and returns its address. Here @var{obstack-ptr} specifies which obstack to allocate the block in; it is the address of the @code{struct obstack} @@ -1658,6 +2123,10 @@ To allocate a block with specified contents, use the function @comment obstack.h @comment GNU @deftypefun {void *} obstack_copy (struct obstack *@var{obstack-ptr}, void *@var{address}, int @var{size}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acunsafe{@acucorrupt{} @acsmem{}}} +@c obstack_copy @mtsrace:obstack-ptr @acucorrupt @acsmem +@c obstack_grow dup @mtsrace:obstack-ptr @acucorrupt @acsmem +@c obstack_finish dup @mtsrace:obstack-ptr @acucorrupt This allocates a block and initializes it by copying @var{size} bytes of data starting at @var{address}. It calls @code{obstack_alloc_failed_handler} if allocation of memory by @@ -1667,6 +2136,10 @@ bytes of data starting at @var{address}. It calls @comment obstack.h @comment GNU @deftypefun {void *} obstack_copy0 (struct obstack *@var{obstack-ptr}, void *@var{address}, int @var{size}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acunsafe{@acucorrupt{} @acsmem{}}} +@c obstack_copy0 @mtsrace:obstack-ptr @acucorrupt @acsmem +@c obstack_grow0 dup @mtsrace:obstack-ptr @acucorrupt @acsmem +@c obstack_finish dup @mtsrace:obstack-ptr @acucorrupt Like @code{obstack_copy}, but appends an extra byte containing a null character. This extra byte is not counted in the argument @var{size}. @end deftypefun @@ -1699,6 +2172,10 @@ in the same obstack. @comment obstack.h @comment GNU @deftypefun void obstack_free (struct obstack *@var{obstack-ptr}, void *@var{object}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acunsafe{@acucorrupt{}}} +@c obstack_free @mtsrace:obstack-ptr @acucorrupt +@c (obstack_free) @mtsrace:obstack-ptr @acucorrupt +@c *freefun dup user-supplied If @var{object} is a null pointer, everything allocated in the obstack is freed. Otherwise, @var{object} must be the address of an object allocated in the obstack. Then @var{object} is freed, along with @@ -1803,6 +2280,13 @@ already added to the growing object will become part of the other object. @comment obstack.h @comment GNU @deftypefun void obstack_blank (struct obstack *@var{obstack-ptr}, int @var{size}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acunsafe{@acucorrupt{} @acsmem{}}} +@c obstack_blank @mtsrace:obstack-ptr @acucorrupt @acsmem +@c _obstack_newchunk @mtsrace:obstack-ptr @acucorrupt @acsmem +@c *chunkfun dup @acsmem +@c *obstack_alloc_failed_handler dup user-supplied +@c *freefun +@c obstack_blank_fast dup @mtsrace:obstack-ptr The most basic function for adding to a growing object is @code{obstack_blank}, which adds space without initializing it. @end deftypefun @@ -1810,6 +2294,10 @@ The most basic function for adding to a growing object is @comment obstack.h @comment GNU @deftypefun void obstack_grow (struct obstack *@var{obstack-ptr}, void *@var{data}, int @var{size}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acunsafe{@acucorrupt{} @acsmem{}}} +@c obstack_grow @mtsrace:obstack-ptr @acucorrupt @acsmem +@c _obstack_newchunk dup @mtsrace:obstack-ptr @acucorrupt @acsmem +@c memcpy ok To add a block of initialized space, use @code{obstack_grow}, which is the growing-object analogue of @code{obstack_copy}. It adds @var{size} bytes of data to the growing object, copying the contents from @@ -1819,6 +2307,12 @@ bytes of data to the growing object, copying the contents from @comment obstack.h @comment GNU @deftypefun void obstack_grow0 (struct obstack *@var{obstack-ptr}, void *@var{data}, int @var{size}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acunsafe{@acucorrupt{} @acsmem{}}} +@c obstack_grow0 @mtsrace:obstack-ptr @acucorrupt @acsmem +@c (no sequence point between storing NUL and incrementing next_free) +@c (multiple changes to next_free => @acucorrupt) +@c _obstack_newchunk dup @mtsrace:obstack-ptr @acucorrupt @acsmem +@c memcpy ok This is the growing-object analogue of @code{obstack_copy0}. It adds @var{size} bytes copied from @var{data}, followed by an additional null character. @@ -1827,6 +2321,10 @@ character. @comment obstack.h @comment GNU @deftypefun void obstack_1grow (struct obstack *@var{obstack-ptr}, char @var{c}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acunsafe{@acucorrupt{} @acsmem{}}} +@c obstack_1grow @mtsrace:obstack-ptr @acucorrupt @acsmem +@c _obstack_newchunk dup @mtsrace:obstack-ptr @acucorrupt @acsmem +@c obstack_1grow_fast dup @mtsrace:obstack-ptr @acucorrupt @acsmem To add one character at a time, use the function @code{obstack_1grow}. It adds a single byte containing @var{c} to the growing object. @end deftypefun @@ -1834,6 +2332,10 @@ It adds a single byte containing @var{c} to the growing object. @comment obstack.h @comment GNU @deftypefun void obstack_ptr_grow (struct obstack *@var{obstack-ptr}, void *@var{data}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acunsafe{@acucorrupt{} @acsmem{}}} +@c obstack_ptr_grow @mtsrace:obstack-ptr @acucorrupt @acsmem +@c _obstack_newchunk dup @mtsrace:obstack-ptr @acucorrupt @acsmem +@c obstack_ptr_grow_fast dup @mtsrace:obstack-ptr Adding the value of a pointer one can use the function @code{obstack_ptr_grow}. It adds @code{sizeof (void *)} bytes containing the value of @var{data}. @@ -1842,6 +2344,10 @@ containing the value of @var{data}. @comment obstack.h @comment GNU @deftypefun void obstack_int_grow (struct obstack *@var{obstack-ptr}, int @var{data}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acunsafe{@acucorrupt{} @acsmem{}}} +@c obstack_int_grow @mtsrace:obstack-ptr @acucorrupt @acsmem +@c _obstack_newchunk dup @mtsrace:obstack-ptr @acucorrupt @acsmem +@c obstack_int_grow_fast dup @mtsrace:obstack-ptr A single value of type @code{int} can be added by using the @code{obstack_int_grow} function. It adds @code{sizeof (int)} bytes to the growing object and initializes them with the value of @var{data}. @@ -1850,6 +2356,8 @@ the growing object and initializes them with the value of @var{data}. @comment obstack.h @comment GNU @deftypefun {void *} obstack_finish (struct obstack *@var{obstack-ptr}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acunsafe{@acucorrupt{}}} +@c obstack_finish @mtsrace:obstack-ptr @acucorrupt When you are finished growing the object, use the function @code{obstack_finish} to close it off and return its final address. @@ -1869,6 +2377,7 @@ declared as follows: @comment obstack.h @comment GNU @deftypefun int obstack_object_size (struct obstack *@var{obstack-ptr}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acsafe{}} This function returns the current size of the growing object, in bytes. Remember to call this function @emph{before} finishing the object. After it is finished, @code{obstack_object_size} will return zero. @@ -1912,6 +2421,7 @@ in the current chunk. It is declared as follows: @comment obstack.h @comment GNU @deftypefun int obstack_room (struct obstack *@var{obstack-ptr}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acsafe{}} This returns the number of bytes that can be added safely to the current growing object (or to an object about to be started) in obstack @var{obstack} using the fast growth functions. @@ -1923,6 +2433,9 @@ for adding data to a growing object: @comment obstack.h @comment GNU @deftypefun void obstack_1grow_fast (struct obstack *@var{obstack-ptr}, char @var{c}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acunsafe{@acucorrupt{} @acsmem{}}} +@c obstack_1grow_fast @mtsrace:obstack-ptr @acucorrupt @acsmem +@c (no sequence point between copying c and incrementing next_free) The function @code{obstack_1grow_fast} adds one byte containing the character @var{c} to the growing object in obstack @var{obstack-ptr}. @end deftypefun @@ -1930,6 +2443,8 @@ character @var{c} to the growing object in obstack @var{obstack-ptr}. @comment obstack.h @comment GNU @deftypefun void obstack_ptr_grow_fast (struct obstack *@var{obstack-ptr}, void *@var{data}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acsafe{}} +@c obstack_ptr_grow_fast @mtsrace:obstack-ptr The function @code{obstack_ptr_grow_fast} adds @code{sizeof (void *)} bytes containing the value of @var{data} to the growing object in obstack @var{obstack-ptr}. @@ -1938,6 +2453,8 @@ obstack @var{obstack-ptr}. @comment obstack.h @comment GNU @deftypefun void obstack_int_grow_fast (struct obstack *@var{obstack-ptr}, int @var{data}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acsafe{}} +@c obstack_int_grow_fast @mtsrace:obstack-ptr The function @code{obstack_int_grow_fast} adds @code{sizeof (int)} bytes containing the value of @var{data} to the growing object in obstack @var{obstack-ptr}. @@ -1946,6 +2463,8 @@ containing the value of @var{data} to the growing object in obstack @comment obstack.h @comment GNU @deftypefun void obstack_blank_fast (struct obstack *@var{obstack-ptr}, int @var{size}) +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acsafe{}} +@c obstack_blank_fast @mtsrace:obstack-ptr The function @code{obstack_blank_fast} adds @var{size} bytes to the growing object in obstack @var{obstack-ptr} without initializing them. @end deftypefun @@ -2004,6 +2523,7 @@ still growing it. @comment obstack.h @comment GNU @deftypefun {void *} obstack_base (struct obstack *@var{obstack-ptr}) +@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acsafe{}} This function returns the tentative address of the beginning of the currently growing object in @var{obstack-ptr}. If you finish the object immediately, it will have that address. If you make it larger first, it @@ -2017,6 +2537,7 @@ chunk). @comment obstack.h @comment GNU @deftypefun {void *} obstack_next_free (struct obstack *@var{obstack-ptr}) +@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acsafe{}} This function returns the address of the first free byte in the current chunk of obstack @var{obstack-ptr}. This is the end of the currently growing object. If no object is growing, @code{obstack_next_free} @@ -2026,6 +2547,8 @@ returns the same value as @code{obstack_base}. @comment obstack.h @comment GNU @deftypefun int obstack_object_size (struct obstack *@var{obstack-ptr}) +@c dup +@safety{@prelim{}@mtsafe{@mtsrace{:obstack-ptr}}@assafe{}@acsafe{}} This function returns the size in bytes of the currently growing object. This is equivalent to @@ -2050,6 +2573,7 @@ this: @comment obstack.h @comment GNU @deftypefn Macro int obstack_alignment_mask (struct obstack *@var{obstack-ptr}) +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} The value is a bit mask; a bit that is 1 indicates that the corresponding bit in the address of an object should be 0. The mask value should be one less than a power of 2; the effect is that all object addresses are @@ -2117,6 +2641,7 @@ not to waste too much memory in the portion of the last chunk not yet used. @comment obstack.h @comment GNU @deftypefn Macro int obstack_chunk_size (struct obstack *@var{obstack-ptr}) +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} This returns the chunk size of the given obstack. @end deftypefn @@ -2236,6 +2761,7 @@ a BSD extension. @comment stdlib.h @comment GNU, BSD @deftypefun {void *} alloca (size_t @var{size}) +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} The return value of @code{alloca} is the address of a block of @var{size} bytes of memory, allocated in the stack frame of the calling function. @end deftypefun @@ -2418,6 +2944,7 @@ system calls. @comment unistd.h @comment BSD @deftypefun int brk (void *@var{addr}) +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} @code{brk} sets the high end of the calling process' data segment to @var{addr}. @@ -2460,6 +2987,8 @@ exceed the process' data storage limit. @comment unistd.h @comment BSD @deftypefun void *sbrk (ptrdiff_t @var{delta}) +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + This function is the same as @code{brk} except that you specify the new end of the data segment as an offset @var{delta} from the current end and on success the return value is the address of the resulting end of @@ -2599,6 +3128,7 @@ this requirement. @comment sys/mman.h @comment POSIX.1b @deftypefun int mlock (const void *@var{addr}, size_t @var{len}) +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} @code{mlock} locks a range of the calling process' virtual pages. @@ -2652,6 +3182,7 @@ wouldn't know what address to tell @code{mlock}. @comment sys/mman.h @comment POSIX.1b @deftypefun int munlock (const void *@var{addr}, size_t @var{len}) +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} @code{munlock} unlocks a range of the calling process' virtual pages. @@ -2664,6 +3195,7 @@ failure. @comment sys/mman.h @comment POSIX.1b @deftypefun int mlockall (int @var{flags}) +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} @code{mlockall} locks all the pages in a process' virtual memory address space, and/or any that are added to it in the future. This includes the @@ -2740,6 +3272,7 @@ with @code{munlockall} and @code{munlock}. @comment sys/mman.h @comment POSIX.1b @deftypefun int munlockall (void) +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} @code{munlockall} unlocks every page in the calling process' virtual address space and turn off @code{MCL_FUTURE} future locking mode. -- 2.7.4