Blame lib/obstack.c

Packit 709fb3
/* obstack.c - subroutines used implicitly by object stack macros
Packit 709fb3
   Copyright (C) 1988-2017 Free Software Foundation, Inc.
Packit 709fb3
   This file is part of the GNU C Library.
Packit 709fb3
Packit 709fb3
   The GNU C Library is free software; you can redistribute it and/or
Packit 709fb3
   modify it under the terms of the GNU General Public
Packit 709fb3
   License as published by the Free Software Foundation; either
Packit 709fb3
   version 3 of the License, or (at your option) any later version.
Packit 709fb3
Packit 709fb3
   The GNU C Library is distributed in the hope that it will be useful,
Packit 709fb3
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 709fb3
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 709fb3
   General Public License for more details.
Packit 709fb3
Packit 709fb3
   You should have received a copy of the GNU General Public
Packit 709fb3
   License along with the GNU C Library; if not, see
Packit 709fb3
   <http://www.gnu.org/licenses/>.  */
Packit 709fb3
Packit 709fb3
Packit 709fb3
#ifdef _LIBC
Packit 709fb3
# include <obstack.h>
Packit 709fb3
#else
Packit 709fb3
# include <config.h>
Packit 709fb3
# include "obstack.h"
Packit 709fb3
#endif
Packit 709fb3
Packit 709fb3
/* NOTE BEFORE MODIFYING THIS FILE: _OBSTACK_INTERFACE_VERSION in
Packit 709fb3
   obstack.h must be incremented whenever callers compiled using an old
Packit 709fb3
   obstack.h can no longer properly call the functions in this file.  */
Packit 709fb3
Packit 709fb3
/* Comment out all this code if we are using the GNU C Library, and are not
Packit 709fb3
   actually compiling the library itself, and the installed library
Packit 709fb3
   supports the same library interface we do.  This code is part of the GNU
Packit 709fb3
   C Library, but also included in many other GNU distributions.  Compiling
Packit 709fb3
   and linking in this code is a waste when using the GNU C library
Packit 709fb3
   (especially if it is a shared library).  Rather than having every GNU
Packit 709fb3
   program understand 'configure --with-gnu-libc' and omit the object
Packit 709fb3
   files, it is simpler to just do this in the source for each such file.  */
Packit 709fb3
#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1
Packit 709fb3
# include <gnu-versions.h>
Packit 709fb3
# if (_GNU_OBSTACK_INTERFACE_VERSION == _OBSTACK_INTERFACE_VERSION	      \
Packit 709fb3
      || (_GNU_OBSTACK_INTERFACE_VERSION == 1				      \
Packit 709fb3
          && _OBSTACK_INTERFACE_VERSION == 2				      \
Packit 709fb3
          && defined SIZEOF_INT && defined SIZEOF_SIZE_T		      \
Packit 709fb3
          && SIZEOF_INT == SIZEOF_SIZE_T))
Packit 709fb3
#  define _OBSTACK_ELIDE_CODE
Packit 709fb3
# endif
Packit 709fb3
#endif
Packit 709fb3
Packit 709fb3
#ifndef _OBSTACK_ELIDE_CODE
Packit 709fb3
/* If GCC, or if an oddball (testing?) host that #defines __alignof__,
Packit 709fb3
   use the already-supplied __alignof__.  Otherwise, this must be Gnulib
Packit 709fb3
   (as glibc assumes GCC); defer to Gnulib's alignof_type.  */
Packit 709fb3
# if !defined __GNUC__ && !defined __alignof__
Packit 709fb3
#  include <alignof.h>
Packit 709fb3
#  define __alignof__(type) alignof_type (type)
Packit 709fb3
# endif
Packit 709fb3
# include <stdlib.h>
Packit 709fb3
# include <stdint.h>
Packit 709fb3
Packit 709fb3
# ifndef MAX
Packit 709fb3
#  define MAX(a,b) ((a) > (b) ? (a) : (b))
Packit 709fb3
# endif
Packit 709fb3
Packit 709fb3
/* Determine default alignment.  */
Packit 709fb3
Packit 709fb3
/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
Packit 709fb3
   But in fact it might be less smart and round addresses to as much as
Packit 709fb3
   DEFAULT_ROUNDING.  So we prepare for it to do that.
Packit 709fb3
Packit 709fb3
   DEFAULT_ALIGNMENT cannot be an enum constant; see gnulib's alignof.h.  */
Packit 709fb3
#define DEFAULT_ALIGNMENT MAX (__alignof__ (long double),		      \
Packit 709fb3
                               MAX (__alignof__ (uintmax_t),		      \
Packit 709fb3
                                    __alignof__ (void *)))
Packit 709fb3
#define DEFAULT_ROUNDING MAX (sizeof (long double),			      \
Packit 709fb3
                               MAX (sizeof (uintmax_t),			      \
Packit 709fb3
                                    sizeof (void *)))
Packit 709fb3
Packit 709fb3
/* Call functions with either the traditional malloc/free calling
Packit 709fb3
   interface, or the mmalloc/mfree interface (that adds an extra first
Packit 709fb3
   argument), based on the value of use_extra_arg.  */
Packit 709fb3
Packit 709fb3
static void *
Packit 709fb3
call_chunkfun (struct obstack *h, size_t size)
Packit 709fb3
{
Packit 709fb3
  if (h->use_extra_arg)
Packit 709fb3
    return h->chunkfun.extra (h->extra_arg, size);
Packit 709fb3
  else
Packit 709fb3
    return h->chunkfun.plain (size);
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
static void
Packit 709fb3
call_freefun (struct obstack *h, void *old_chunk)
Packit 709fb3
{
Packit 709fb3
  if (h->use_extra_arg)
Packit 709fb3
    h->freefun.extra (h->extra_arg, old_chunk);
Packit 709fb3
  else
Packit 709fb3
    h->freefun.plain (old_chunk);
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
Packit 709fb3
/* Initialize an obstack H for use.  Specify chunk size SIZE (0 means default).
Packit 709fb3
   Objects start on multiples of ALIGNMENT (0 means use default).
Packit 709fb3
Packit 709fb3
   Return nonzero if successful, calls obstack_alloc_failed_handler if
Packit 709fb3
   allocation fails.  */
Packit 709fb3
Packit 709fb3
static int
Packit 709fb3
_obstack_begin_worker (struct obstack *h,
Packit 709fb3
                       _OBSTACK_SIZE_T size, _OBSTACK_SIZE_T alignment)
Packit 709fb3
{
Packit 709fb3
  struct _obstack_chunk *chunk; /* points to new chunk */
Packit 709fb3
Packit 709fb3
  if (alignment == 0)
Packit 709fb3
    alignment = DEFAULT_ALIGNMENT;
Packit 709fb3
  if (size == 0)
Packit 709fb3
    /* Default size is what GNU malloc can fit in a 4096-byte block.  */
Packit 709fb3
    {
Packit 709fb3
      /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
Packit 709fb3
         Use the values for range checking, because if range checking is off,
Packit 709fb3
         the extra bytes won't be missed terribly, but if range checking is on
Packit 709fb3
         and we used a larger request, a whole extra 4096 bytes would be
Packit 709fb3
         allocated.
Packit 709fb3
Packit 709fb3
         These number are irrelevant to the new GNU malloc.  I suspect it is
Packit 709fb3
         less sensitive to the size of the request.  */
Packit 709fb3
      int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
Packit 709fb3
                    + 4 + DEFAULT_ROUNDING - 1)
Packit 709fb3
                   & ~(DEFAULT_ROUNDING - 1));
Packit 709fb3
      size = 4096 - extra;
Packit 709fb3
    }
Packit 709fb3
Packit 709fb3
  h->chunk_size = size;
Packit 709fb3
  h->alignment_mask = alignment - 1;
Packit 709fb3
Packit 709fb3
  chunk = h->chunk = call_chunkfun (h, h->chunk_size);
Packit 709fb3
  if (!chunk)
Packit 709fb3
    (*obstack_alloc_failed_handler) ();
Packit 709fb3
  h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
Packit 709fb3
                                               alignment - 1);
Packit 709fb3
  h->chunk_limit = chunk->limit = (char *) chunk + h->chunk_size;
Packit 709fb3
  chunk->prev = 0;
Packit 709fb3
  /* The initial chunk now contains no empty object.  */
Packit 709fb3
  h->maybe_empty_object = 0;
Packit 709fb3
  h->alloc_failed = 0;
Packit 709fb3
  return 1;
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
int
Packit 709fb3
_obstack_begin (struct obstack *h,
Packit 709fb3
                _OBSTACK_SIZE_T size, _OBSTACK_SIZE_T alignment,
Packit 709fb3
                void *(*chunkfun) (size_t),
Packit 709fb3
                void (*freefun) (void *))
Packit 709fb3
{
Packit 709fb3
  h->chunkfun.plain = chunkfun;
Packit 709fb3
  h->freefun.plain = freefun;
Packit 709fb3
  h->use_extra_arg = 0;
Packit 709fb3
  return _obstack_begin_worker (h, size, alignment);
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
int
Packit 709fb3
_obstack_begin_1 (struct obstack *h,
Packit 709fb3
                  _OBSTACK_SIZE_T size, _OBSTACK_SIZE_T alignment,
Packit 709fb3
                  void *(*chunkfun) (void *, size_t),
Packit 709fb3
                  void (*freefun) (void *, void *),
Packit 709fb3
                  void *arg)
Packit 709fb3
{
Packit 709fb3
  h->chunkfun.extra = chunkfun;
Packit 709fb3
  h->freefun.extra = freefun;
Packit 709fb3
  h->extra_arg = arg;
Packit 709fb3
  h->use_extra_arg = 1;
Packit 709fb3
  return _obstack_begin_worker (h, size, alignment);
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
/* Allocate a new current chunk for the obstack *H
Packit 709fb3
   on the assumption that LENGTH bytes need to be added
Packit 709fb3
   to the current object, or a new object of length LENGTH allocated.
Packit 709fb3
   Copies any partial object from the end of the old chunk
Packit 709fb3
   to the beginning of the new one.  */
Packit 709fb3
Packit 709fb3
void
Packit 709fb3
_obstack_newchunk (struct obstack *h, _OBSTACK_SIZE_T length)
Packit 709fb3
{
Packit 709fb3
  struct _obstack_chunk *old_chunk = h->chunk;
Packit 709fb3
  struct _obstack_chunk *new_chunk = 0;
Packit 709fb3
  size_t obj_size = h->next_free - h->object_base;
Packit 709fb3
  char *object_base;
Packit 709fb3
Packit 709fb3
  /* Compute size for new chunk.  */
Packit 709fb3
  size_t sum1 = obj_size + length;
Packit 709fb3
  size_t sum2 = sum1 + h->alignment_mask;
Packit 709fb3
  size_t new_size = sum2 + (obj_size >> 3) + 100;
Packit 709fb3
  if (new_size < sum2)
Packit 709fb3
    new_size = sum2;
Packit 709fb3
  if (new_size < h->chunk_size)
Packit 709fb3
    new_size = h->chunk_size;
Packit 709fb3
Packit 709fb3
  /* Allocate and initialize the new chunk.  */
Packit 709fb3
  if (obj_size <= sum1 && sum1 <= sum2)
Packit 709fb3
    new_chunk = call_chunkfun (h, new_size);
Packit 709fb3
  if (!new_chunk)
Packit 709fb3
    (*obstack_alloc_failed_handler)();
Packit 709fb3
  h->chunk = new_chunk;
Packit 709fb3
  new_chunk->prev = old_chunk;
Packit 709fb3
  new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
Packit 709fb3
Packit 709fb3
  /* Compute an aligned object_base in the new chunk */
Packit 709fb3
  object_base =
Packit 709fb3
    __PTR_ALIGN ((char *) new_chunk, new_chunk->contents, h->alignment_mask);
Packit 709fb3
Packit 709fb3
  /* Move the existing object to the new chunk.  */
Packit 709fb3
  memcpy (object_base, h->object_base, obj_size);
Packit 709fb3
Packit 709fb3
  /* If the object just copied was the only data in OLD_CHUNK,
Packit 709fb3
     free that chunk and remove it from the chain.
Packit 709fb3
     But not if that chunk might contain an empty object.  */
Packit 709fb3
  if (!h->maybe_empty_object
Packit 709fb3
      && (h->object_base
Packit 709fb3
          == __PTR_ALIGN ((char *) old_chunk, old_chunk->contents,
Packit 709fb3
                          h->alignment_mask)))
Packit 709fb3
    {
Packit 709fb3
      new_chunk->prev = old_chunk->prev;
Packit 709fb3
      call_freefun (h, old_chunk);
Packit 709fb3
    }
Packit 709fb3
Packit 709fb3
  h->object_base = object_base;
Packit 709fb3
  h->next_free = h->object_base + obj_size;
Packit 709fb3
  /* The new chunk certainly contains no empty object yet.  */
Packit 709fb3
  h->maybe_empty_object = 0;
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
/* Return nonzero if object OBJ has been allocated from obstack H.
Packit 709fb3
   This is here for debugging.
Packit 709fb3
   If you use it in a program, you are probably losing.  */
Packit 709fb3
Packit 709fb3
/* Suppress -Wmissing-prototypes warning.  We don't want to declare this in
Packit 709fb3
   obstack.h because it is just for debugging.  */
Packit 709fb3
int _obstack_allocated_p (struct obstack *h, void *obj) __attribute_pure__;
Packit 709fb3
Packit 709fb3
int
Packit 709fb3
_obstack_allocated_p (struct obstack *h, void *obj)
Packit 709fb3
{
Packit 709fb3
  struct _obstack_chunk *lp;    /* below addr of any objects in this chunk */
Packit 709fb3
  struct _obstack_chunk *plp;   /* point to previous chunk if any */
Packit 709fb3
Packit 709fb3
  lp = (h)->chunk;
Packit 709fb3
  /* We use >= rather than > since the object cannot be exactly at
Packit 709fb3
     the beginning of the chunk but might be an empty object exactly
Packit 709fb3
     at the end of an adjacent chunk.  */
Packit 709fb3
  while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
Packit 709fb3
    {
Packit 709fb3
      plp = lp->prev;
Packit 709fb3
      lp = plp;
Packit 709fb3
    }
Packit 709fb3
  return lp != 0;
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
/* Free objects in obstack H, including OBJ and everything allocate
Packit 709fb3
   more recently than OBJ.  If OBJ is zero, free everything in H.  */
Packit 709fb3
Packit 709fb3
void
Packit 709fb3
_obstack_free (struct obstack *h, void *obj)
Packit 709fb3
{
Packit 709fb3
  struct _obstack_chunk *lp;    /* below addr of any objects in this chunk */
Packit 709fb3
  struct _obstack_chunk *plp;   /* point to previous chunk if any */
Packit 709fb3
Packit 709fb3
  lp = h->chunk;
Packit 709fb3
  /* We use >= because there cannot be an object at the beginning of a chunk.
Packit 709fb3
     But there can be an empty object at that address
Packit 709fb3
     at the end of another chunk.  */
Packit 709fb3
  while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
Packit 709fb3
    {
Packit 709fb3
      plp = lp->prev;
Packit 709fb3
      call_freefun (h, lp);
Packit 709fb3
      lp = plp;
Packit 709fb3
      /* If we switch chunks, we can't tell whether the new current
Packit 709fb3
         chunk contains an empty object, so assume that it may.  */
Packit 709fb3
      h->maybe_empty_object = 1;
Packit 709fb3
    }
Packit 709fb3
  if (lp)
Packit 709fb3
    {
Packit 709fb3
      h->object_base = h->next_free = (char *) (obj);
Packit 709fb3
      h->chunk_limit = lp->limit;
Packit 709fb3
      h->chunk = lp;
Packit 709fb3
    }
Packit 709fb3
  else if (obj != 0)
Packit 709fb3
    /* obj is not in any of the chunks! */
Packit 709fb3
    abort ();
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
_OBSTACK_SIZE_T
Packit 709fb3
_obstack_memory_used (struct obstack *h)
Packit 709fb3
{
Packit 709fb3
  struct _obstack_chunk *lp;
Packit 709fb3
  _OBSTACK_SIZE_T nbytes = 0;
Packit 709fb3
Packit 709fb3
  for (lp = h->chunk; lp != 0; lp = lp->prev)
Packit 709fb3
    {
Packit 709fb3
      nbytes += lp->limit - (char *) lp;
Packit 709fb3
    }
Packit 709fb3
  return nbytes;
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
# ifndef _OBSTACK_NO_ERROR_HANDLER
Packit 709fb3
/* Define the error handler.  */
Packit 709fb3
#  include <stdio.h>
Packit 709fb3
Packit 709fb3
/* Exit value used when 'print_and_abort' is used.  */
Packit 709fb3
#  ifdef _LIBC
Packit 709fb3
int obstack_exit_failure = EXIT_FAILURE;
Packit 709fb3
#  else
Packit 709fb3
#   include "exitfail.h"
Packit 709fb3
#   define obstack_exit_failure exit_failure
Packit 709fb3
#  endif
Packit 709fb3
Packit 709fb3
#  ifdef _LIBC
Packit 709fb3
#   include <libintl.h>
Packit 709fb3
#  else
Packit 709fb3
#   include "gettext.h"
Packit 709fb3
#  endif
Packit 709fb3
#  ifndef _
Packit 709fb3
#   define _(msgid) gettext (msgid)
Packit 709fb3
#  endif
Packit 709fb3
Packit 709fb3
#  ifdef _LIBC
Packit 709fb3
#   include <libio/iolibio.h>
Packit 709fb3
#  endif
Packit 709fb3
Packit 709fb3
static _Noreturn void
Packit 709fb3
print_and_abort (void)
Packit 709fb3
{
Packit 709fb3
  /* Don't change any of these strings.  Yes, it would be possible to add
Packit 709fb3
     the newline to the string and use fputs or so.  But this must not
Packit 709fb3
     happen because the "memory exhausted" message appears in other places
Packit 709fb3
     like this and the translation should be reused instead of creating
Packit 709fb3
     a very similar string which requires a separate translation.  */
Packit 709fb3
#  ifdef _LIBC
Packit 709fb3
  (void) __fxprintf (NULL, "%s\n", _("memory exhausted"));
Packit 709fb3
#  else
Packit 709fb3
  fprintf (stderr, "%s\n", _("memory exhausted"));
Packit 709fb3
#  endif
Packit 709fb3
  exit (obstack_exit_failure);
Packit 709fb3
}
Packit 709fb3
Packit 709fb3
/* The functions allocating more room by calling 'obstack_chunk_alloc'
Packit 709fb3
   jump to the handler pointed to by 'obstack_alloc_failed_handler'.
Packit 709fb3
   This can be set to a user defined function which should either
Packit 709fb3
   abort gracefully or use longjump - but shouldn't return.  This
Packit 709fb3
   variable by default points to the internal function
Packit 709fb3
   'print_and_abort'.  */
Packit 709fb3
__attribute_noreturn__ void (*obstack_alloc_failed_handler) (void)
Packit 709fb3
  = print_and_abort;
Packit 709fb3
# endif /* !_OBSTACK_NO_ERROR_HANDLER */
Packit 709fb3
#endif /* !_OBSTACK_ELIDE_CODE */