12a6b7db3Sskrll /* obstack.c - subroutines used implicitly by object stack macros
2*f22f0ef4Schristos Copyright (C) 1988-2022 Free Software Foundation, Inc.
35ba6b03cSchristos This file is part of the GNU C Library.
42a6b7db3Sskrll
55ba6b03cSchristos The GNU C Library is free software; you can redistribute it and/or
65ba6b03cSchristos modify it under the terms of the GNU Lesser General Public
75ba6b03cSchristos License as published by the Free Software Foundation; either
85ba6b03cSchristos version 2.1 of the License, or (at your option) any later version.
92a6b7db3Sskrll
105ba6b03cSchristos The GNU C Library is distributed in the hope that it will be useful,
112a6b7db3Sskrll but WITHOUT ANY WARRANTY; without even the implied warranty of
125ba6b03cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
135ba6b03cSchristos Lesser General Public License for more details.
142a6b7db3Sskrll
155ba6b03cSchristos You should have received a copy of the GNU Lesser General Public
165ba6b03cSchristos License along with the GNU C Library; if not, see
175ba6b03cSchristos <http://www.gnu.org/licenses/>. */
182a6b7db3Sskrll
195ba6b03cSchristos
205ba6b03cSchristos #ifdef _LIBC
215ba6b03cSchristos # include <obstack.h>
225ba6b03cSchristos #else
232a6b7db3Sskrll # include <config.h>
245ba6b03cSchristos # include "obstack.h"
252a6b7db3Sskrll #endif
262a6b7db3Sskrll
275ba6b03cSchristos /* NOTE BEFORE MODIFYING THIS FILE: _OBSTACK_INTERFACE_VERSION in
285ba6b03cSchristos obstack.h must be incremented whenever callers compiled using an old
295ba6b03cSchristos obstack.h can no longer properly call the functions in this file. */
302a6b7db3Sskrll
312a6b7db3Sskrll /* Comment out all this code if we are using the GNU C Library, and are not
322a6b7db3Sskrll actually compiling the library itself, and the installed library
332a6b7db3Sskrll supports the same library interface we do. This code is part of the GNU
342a6b7db3Sskrll C Library, but also included in many other GNU distributions. Compiling
352a6b7db3Sskrll and linking in this code is a waste when using the GNU C library
362a6b7db3Sskrll (especially if it is a shared library). Rather than having every GNU
375ba6b03cSchristos program understand 'configure --with-gnu-libc' and omit the object
382a6b7db3Sskrll files, it is simpler to just do this in the source for each such file. */
395ba6b03cSchristos #if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1
402a6b7db3Sskrll # include <gnu-versions.h>
415ba6b03cSchristos # if (_GNU_OBSTACK_INTERFACE_VERSION == _OBSTACK_INTERFACE_VERSION \
425ba6b03cSchristos || (_GNU_OBSTACK_INTERFACE_VERSION == 1 \
435ba6b03cSchristos && _OBSTACK_INTERFACE_VERSION == 2 \
445ba6b03cSchristos && defined SIZEOF_INT && defined SIZEOF_SIZE_T \
455ba6b03cSchristos && SIZEOF_INT == SIZEOF_SIZE_T))
465ba6b03cSchristos # define _OBSTACK_ELIDE_CODE
472a6b7db3Sskrll # endif
482a6b7db3Sskrll #endif
492a6b7db3Sskrll
505ba6b03cSchristos #ifndef _OBSTACK_ELIDE_CODE
515ba6b03cSchristos /* If GCC, or if an oddball (testing?) host that #defines __alignof__,
525ba6b03cSchristos use the already-supplied __alignof__. Otherwise, this must be Gnulib
535ba6b03cSchristos (as glibc assumes GCC); defer to Gnulib's alignof_type. */
545ba6b03cSchristos # if !defined __GNUC__ && !defined __IBM__ALIGNOF__ && !defined __alignof__
555ba6b03cSchristos # if defined __cplusplus
565ba6b03cSchristos template <class type> struct alignof_helper { char __slot1; type __slot2; };
575ba6b03cSchristos # define __alignof__(type) offsetof (alignof_helper<type>, __slot2)
585ba6b03cSchristos # else
595ba6b03cSchristos # define __alignof__(type) \
605ba6b03cSchristos offsetof (struct { char __slot1; type __slot2; }, __slot2)
615ba6b03cSchristos # endif
625ba6b03cSchristos # endif
635ba6b03cSchristos # include <stdlib.h>
645ba6b03cSchristos # include <stdint.h>
652a6b7db3Sskrll
665ba6b03cSchristos # ifndef MAX
675ba6b03cSchristos # define MAX(a,b) ((a) > (b) ? (a) : (b))
685ba6b03cSchristos # endif
692a6b7db3Sskrll
702a6b7db3Sskrll /* Determine default alignment. */
715ba6b03cSchristos
722a6b7db3Sskrll /* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
732a6b7db3Sskrll But in fact it might be less smart and round addresses to as much as
745ba6b03cSchristos DEFAULT_ROUNDING. So we prepare for it to do that.
752a6b7db3Sskrll
765ba6b03cSchristos DEFAULT_ALIGNMENT cannot be an enum constant; see gnulib's alignof.h. */
775ba6b03cSchristos #define DEFAULT_ALIGNMENT MAX (__alignof__ (long double), \
785ba6b03cSchristos MAX (__alignof__ (uintmax_t), \
795ba6b03cSchristos __alignof__ (void *)))
805ba6b03cSchristos #define DEFAULT_ROUNDING MAX (sizeof (long double), \
815ba6b03cSchristos MAX (sizeof (uintmax_t), \
825ba6b03cSchristos sizeof (void *)))
835ba6b03cSchristos
845ba6b03cSchristos /* Call functions with either the traditional malloc/free calling
855ba6b03cSchristos interface, or the mmalloc/mfree interface (that adds an extra first
865ba6b03cSchristos argument), based on the value of use_extra_arg. */
875ba6b03cSchristos
885ba6b03cSchristos static void *
call_chunkfun(struct obstack * h,size_t size)895ba6b03cSchristos call_chunkfun (struct obstack *h, size_t size)
905ba6b03cSchristos {
915ba6b03cSchristos if (h->use_extra_arg)
925ba6b03cSchristos return h->chunkfun.extra (h->extra_arg, size);
935ba6b03cSchristos else
945ba6b03cSchristos return h->chunkfun.plain (size);
955ba6b03cSchristos }
965ba6b03cSchristos
975ba6b03cSchristos static void
call_freefun(struct obstack * h,void * old_chunk)985ba6b03cSchristos call_freefun (struct obstack *h, void *old_chunk)
995ba6b03cSchristos {
1005ba6b03cSchristos if (h->use_extra_arg)
1015ba6b03cSchristos h->freefun.extra (h->extra_arg, old_chunk);
1025ba6b03cSchristos else
1035ba6b03cSchristos h->freefun.plain (old_chunk);
1045ba6b03cSchristos }
1052a6b7db3Sskrll
1062a6b7db3Sskrll
1072a6b7db3Sskrll /* Initialize an obstack H for use. Specify chunk size SIZE (0 means default).
1082a6b7db3Sskrll Objects start on multiples of ALIGNMENT (0 means use default).
1092a6b7db3Sskrll
1105ba6b03cSchristos Return nonzero if successful, calls obstack_alloc_failed_handler if
1115ba6b03cSchristos allocation fails. */
1122a6b7db3Sskrll
1135ba6b03cSchristos static int
_obstack_begin_worker(struct obstack * h,_OBSTACK_SIZE_T size,_OBSTACK_SIZE_T alignment)1145ba6b03cSchristos _obstack_begin_worker (struct obstack *h,
1155ba6b03cSchristos _OBSTACK_SIZE_T size, _OBSTACK_SIZE_T alignment)
1162a6b7db3Sskrll {
1175ba6b03cSchristos struct _obstack_chunk *chunk; /* points to new chunk */
1182a6b7db3Sskrll
1192a6b7db3Sskrll if (alignment == 0)
1205ba6b03cSchristos alignment = DEFAULT_ALIGNMENT;
1212a6b7db3Sskrll if (size == 0)
1222a6b7db3Sskrll /* Default size is what GNU malloc can fit in a 4096-byte block. */
1232a6b7db3Sskrll {
1242a6b7db3Sskrll /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
1252a6b7db3Sskrll Use the values for range checking, because if range checking is off,
1262a6b7db3Sskrll the extra bytes won't be missed terribly, but if range checking is on
1272a6b7db3Sskrll and we used a larger request, a whole extra 4096 bytes would be
1282a6b7db3Sskrll allocated.
1292a6b7db3Sskrll
1302a6b7db3Sskrll These number are irrelevant to the new GNU malloc. I suspect it is
1312a6b7db3Sskrll less sensitive to the size of the request. */
1322a6b7db3Sskrll int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
1332a6b7db3Sskrll + 4 + DEFAULT_ROUNDING - 1)
1342a6b7db3Sskrll & ~(DEFAULT_ROUNDING - 1));
1352a6b7db3Sskrll size = 4096 - extra;
1362a6b7db3Sskrll }
1372a6b7db3Sskrll
1382a6b7db3Sskrll h->chunk_size = size;
1392a6b7db3Sskrll h->alignment_mask = alignment - 1;
1402a6b7db3Sskrll
1415ba6b03cSchristos chunk = (struct _obstack_chunk *) call_chunkfun (h, h->chunk_size);
1422a6b7db3Sskrll if (!chunk)
1432a6b7db3Sskrll (*obstack_alloc_failed_handler) ();
1445ba6b03cSchristos h->chunk = chunk;
1455ba6b03cSchristos h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
1465ba6b03cSchristos alignment - 1);
1475ba6b03cSchristos h->chunk_limit = chunk->limit = (char *) chunk + h->chunk_size;
1482a6b7db3Sskrll chunk->prev = 0;
1492a6b7db3Sskrll /* The initial chunk now contains no empty object. */
1502a6b7db3Sskrll h->maybe_empty_object = 0;
1512a6b7db3Sskrll h->alloc_failed = 0;
1522a6b7db3Sskrll return 1;
1532a6b7db3Sskrll }
1542a6b7db3Sskrll
1552a6b7db3Sskrll int
_obstack_begin(struct obstack * h,_OBSTACK_SIZE_T size,_OBSTACK_SIZE_T alignment,void * (* chunkfun)(size_t),void (* freefun)(void *))1565ba6b03cSchristos _obstack_begin (struct obstack *h,
1575ba6b03cSchristos _OBSTACK_SIZE_T size, _OBSTACK_SIZE_T alignment,
1585ba6b03cSchristos void *(*chunkfun) (size_t),
1595ba6b03cSchristos void (*freefun) (void *))
1602a6b7db3Sskrll {
1615ba6b03cSchristos h->chunkfun.plain = chunkfun;
1625ba6b03cSchristos h->freefun.plain = freefun;
1635ba6b03cSchristos h->use_extra_arg = 0;
1645ba6b03cSchristos return _obstack_begin_worker (h, size, alignment);
1652a6b7db3Sskrll }
1662a6b7db3Sskrll
1675ba6b03cSchristos int
_obstack_begin_1(struct obstack * h,_OBSTACK_SIZE_T size,_OBSTACK_SIZE_T alignment,void * (* chunkfun)(void *,size_t),void (* freefun)(void *,void *),void * arg)1685ba6b03cSchristos _obstack_begin_1 (struct obstack *h,
1695ba6b03cSchristos _OBSTACK_SIZE_T size, _OBSTACK_SIZE_T alignment,
1705ba6b03cSchristos void *(*chunkfun) (void *, size_t),
1715ba6b03cSchristos void (*freefun) (void *, void *),
1725ba6b03cSchristos void *arg)
1735ba6b03cSchristos {
1745ba6b03cSchristos h->chunkfun.extra = chunkfun;
1755ba6b03cSchristos h->freefun.extra = freefun;
1762a6b7db3Sskrll h->extra_arg = arg;
1772a6b7db3Sskrll h->use_extra_arg = 1;
1785ba6b03cSchristos return _obstack_begin_worker (h, size, alignment);
1792a6b7db3Sskrll }
1802a6b7db3Sskrll
1812a6b7db3Sskrll /* Allocate a new current chunk for the obstack *H
1822a6b7db3Sskrll on the assumption that LENGTH bytes need to be added
1832a6b7db3Sskrll to the current object, or a new object of length LENGTH allocated.
1842a6b7db3Sskrll Copies any partial object from the end of the old chunk
1852a6b7db3Sskrll to the beginning of the new one. */
1862a6b7db3Sskrll
1872a6b7db3Sskrll void
_obstack_newchunk(struct obstack * h,_OBSTACK_SIZE_T length)1885ba6b03cSchristos _obstack_newchunk (struct obstack *h, _OBSTACK_SIZE_T length)
1892a6b7db3Sskrll {
1905ba6b03cSchristos struct _obstack_chunk *old_chunk = h->chunk;
1915ba6b03cSchristos struct _obstack_chunk *new_chunk = 0;
1925ba6b03cSchristos size_t obj_size = h->next_free - h->object_base;
1935ba6b03cSchristos char *object_base;
1942a6b7db3Sskrll
1952a6b7db3Sskrll /* Compute size for new chunk. */
1965ba6b03cSchristos size_t sum1 = obj_size + length;
1975ba6b03cSchristos size_t sum2 = sum1 + h->alignment_mask;
1985ba6b03cSchristos size_t new_size = sum2 + (obj_size >> 3) + 100;
1995ba6b03cSchristos if (new_size < sum2)
2005ba6b03cSchristos new_size = sum2;
2012a6b7db3Sskrll if (new_size < h->chunk_size)
2022a6b7db3Sskrll new_size = h->chunk_size;
2032a6b7db3Sskrll
2042a6b7db3Sskrll /* Allocate and initialize the new chunk. */
2055ba6b03cSchristos if (obj_size <= sum1 && sum1 <= sum2)
2065ba6b03cSchristos new_chunk = (struct _obstack_chunk *) call_chunkfun (h, new_size);
2072a6b7db3Sskrll if (!new_chunk)
2082a6b7db3Sskrll (*obstack_alloc_failed_handler)();
2092a6b7db3Sskrll h->chunk = new_chunk;
2102a6b7db3Sskrll new_chunk->prev = old_chunk;
2112a6b7db3Sskrll new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
2122a6b7db3Sskrll
2135ba6b03cSchristos /* Compute an aligned object_base in the new chunk */
2145ba6b03cSchristos object_base =
2155ba6b03cSchristos __PTR_ALIGN ((char *) new_chunk, new_chunk->contents, h->alignment_mask);
2165ba6b03cSchristos
2175ba6b03cSchristos /* Move the existing object to the new chunk. */
2185ba6b03cSchristos memcpy (object_base, h->object_base, obj_size);
2192a6b7db3Sskrll
2202a6b7db3Sskrll /* If the object just copied was the only data in OLD_CHUNK,
2212a6b7db3Sskrll free that chunk and remove it from the chain.
2222a6b7db3Sskrll But not if that chunk might contain an empty object. */
2235ba6b03cSchristos if (!h->maybe_empty_object
2245ba6b03cSchristos && (h->object_base
2255ba6b03cSchristos == __PTR_ALIGN ((char *) old_chunk, old_chunk->contents,
2265ba6b03cSchristos h->alignment_mask)))
2272a6b7db3Sskrll {
2282a6b7db3Sskrll new_chunk->prev = old_chunk->prev;
2295ba6b03cSchristos call_freefun (h, old_chunk);
2302a6b7db3Sskrll }
2312a6b7db3Sskrll
2325ba6b03cSchristos h->object_base = object_base;
2332a6b7db3Sskrll h->next_free = h->object_base + obj_size;
2342a6b7db3Sskrll /* The new chunk certainly contains no empty object yet. */
2352a6b7db3Sskrll h->maybe_empty_object = 0;
2362a6b7db3Sskrll }
2372a6b7db3Sskrll
2382a6b7db3Sskrll /* Return nonzero if object OBJ has been allocated from obstack H.
2392a6b7db3Sskrll This is here for debugging.
2402a6b7db3Sskrll If you use it in a program, you are probably losing. */
2412a6b7db3Sskrll
2422a6b7db3Sskrll /* Suppress -Wmissing-prototypes warning. We don't want to declare this in
2432a6b7db3Sskrll obstack.h because it is just for debugging. */
2445ba6b03cSchristos int _obstack_allocated_p (struct obstack *h, void *obj) __attribute_pure__;
2452a6b7db3Sskrll
2462a6b7db3Sskrll int
_obstack_allocated_p(struct obstack * h,void * obj)2475ba6b03cSchristos _obstack_allocated_p (struct obstack *h, void *obj)
2482a6b7db3Sskrll {
2495ba6b03cSchristos struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
2505ba6b03cSchristos struct _obstack_chunk *plp; /* point to previous chunk if any */
2512a6b7db3Sskrll
2522a6b7db3Sskrll lp = (h)->chunk;
2532a6b7db3Sskrll /* We use >= rather than > since the object cannot be exactly at
2542a6b7db3Sskrll the beginning of the chunk but might be an empty object exactly
2552a6b7db3Sskrll at the end of an adjacent chunk. */
2565ba6b03cSchristos while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
2572a6b7db3Sskrll {
2582a6b7db3Sskrll plp = lp->prev;
2592a6b7db3Sskrll lp = plp;
2602a6b7db3Sskrll }
2612a6b7db3Sskrll return lp != 0;
2622a6b7db3Sskrll }
2635ba6b03cSchristos
2642a6b7db3Sskrll /* Free objects in obstack H, including OBJ and everything allocate
2652a6b7db3Sskrll more recently than OBJ. If OBJ is zero, free everything in H. */
2662a6b7db3Sskrll
2672a6b7db3Sskrll void
_obstack_free(struct obstack * h,void * obj)2685ba6b03cSchristos _obstack_free (struct obstack *h, void *obj)
2692a6b7db3Sskrll {
2705ba6b03cSchristos struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
2715ba6b03cSchristos struct _obstack_chunk *plp; /* point to previous chunk if any */
2722a6b7db3Sskrll
2732a6b7db3Sskrll lp = h->chunk;
2742a6b7db3Sskrll /* We use >= because there cannot be an object at the beginning of a chunk.
2752a6b7db3Sskrll But there can be an empty object at that address
2762a6b7db3Sskrll at the end of another chunk. */
2775ba6b03cSchristos while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
2782a6b7db3Sskrll {
2792a6b7db3Sskrll plp = lp->prev;
2805ba6b03cSchristos call_freefun (h, lp);
2812a6b7db3Sskrll lp = plp;
2822a6b7db3Sskrll /* If we switch chunks, we can't tell whether the new current
2832a6b7db3Sskrll chunk contains an empty object, so assume that it may. */
2842a6b7db3Sskrll h->maybe_empty_object = 1;
2852a6b7db3Sskrll }
2862a6b7db3Sskrll if (lp)
2872a6b7db3Sskrll {
2882a6b7db3Sskrll h->object_base = h->next_free = (char *) (obj);
2892a6b7db3Sskrll h->chunk_limit = lp->limit;
2902a6b7db3Sskrll h->chunk = lp;
2912a6b7db3Sskrll }
2922a6b7db3Sskrll else if (obj != 0)
2932a6b7db3Sskrll /* obj is not in any of the chunks! */
2942a6b7db3Sskrll abort ();
2952a6b7db3Sskrll }
2962a6b7db3Sskrll
2975ba6b03cSchristos _OBSTACK_SIZE_T
_obstack_memory_used(struct obstack * h)2982a6b7db3Sskrll _obstack_memory_used (struct obstack *h)
2992a6b7db3Sskrll {
3005ba6b03cSchristos struct _obstack_chunk *lp;
3015ba6b03cSchristos _OBSTACK_SIZE_T nbytes = 0;
3022a6b7db3Sskrll
3032a6b7db3Sskrll for (lp = h->chunk; lp != 0; lp = lp->prev)
3042a6b7db3Sskrll {
3052a6b7db3Sskrll nbytes += lp->limit - (char *) lp;
3062a6b7db3Sskrll }
3072a6b7db3Sskrll return nbytes;
3082a6b7db3Sskrll }
3095ba6b03cSchristos
3105ba6b03cSchristos # ifndef _OBSTACK_NO_ERROR_HANDLER
3112a6b7db3Sskrll /* Define the error handler. */
3125ba6b03cSchristos # include <stdio.h>
3135ba6b03cSchristos
3145ba6b03cSchristos /* Exit value used when 'print_and_abort' is used. */
3155ba6b03cSchristos # ifdef _LIBC
3165ba6b03cSchristos int obstack_exit_failure = EXIT_FAILURE;
3175ba6b03cSchristos # else
3185ba6b03cSchristos # ifndef EXIT_FAILURE
3195ba6b03cSchristos # define EXIT_FAILURE 1
3205ba6b03cSchristos # endif
3215ba6b03cSchristos # define obstack_exit_failure EXIT_FAILURE
3225ba6b03cSchristos # endif
3235ba6b03cSchristos
3245ba6b03cSchristos # if defined _LIBC || (HAVE_LIBINTL_H && ENABLE_NLS)
3252a6b7db3Sskrll # include <libintl.h>
3262a6b7db3Sskrll # ifndef _
3275ba6b03cSchristos # define _(msgid) gettext (msgid)
3282a6b7db3Sskrll # endif
3292a6b7db3Sskrll # else
3305ba6b03cSchristos # ifndef _
3315ba6b03cSchristos # define _(msgid) (msgid)
3322a6b7db3Sskrll # endif
3332a6b7db3Sskrll # endif
3342a6b7db3Sskrll
3355ba6b03cSchristos # if !(defined _Noreturn \
3365ba6b03cSchristos || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112))
3375ba6b03cSchristos # if ((defined __GNUC__ \
3385ba6b03cSchristos && (__GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))) \
3395ba6b03cSchristos || (defined __SUNPRO_C && __SUNPRO_C >= 0x5110))
3405ba6b03cSchristos # define _Noreturn __attribute__ ((__noreturn__))
3415ba6b03cSchristos # elif defined _MSC_VER && _MSC_VER >= 1200
3425ba6b03cSchristos # define _Noreturn __declspec (noreturn)
3435ba6b03cSchristos # else
3445ba6b03cSchristos # define _Noreturn
3455ba6b03cSchristos # endif
3465ba6b03cSchristos # endif
3475ba6b03cSchristos
3485ba6b03cSchristos # ifdef _LIBC
3495ba6b03cSchristos # include <libio/iolibio.h>
3505ba6b03cSchristos # endif
3515ba6b03cSchristos
3525ba6b03cSchristos static _Noreturn void
print_and_abort(void)3532a6b7db3Sskrll print_and_abort (void)
3542a6b7db3Sskrll {
3555ba6b03cSchristos /* Don't change any of these strings. Yes, it would be possible to add
3565ba6b03cSchristos the newline to the string and use fputs or so. But this must not
3575ba6b03cSchristos happen because the "memory exhausted" message appears in other places
3585ba6b03cSchristos like this and the translation should be reused instead of creating
3595ba6b03cSchristos a very similar string which requires a separate translation. */
3605ba6b03cSchristos # ifdef _LIBC
3615ba6b03cSchristos (void) __fxprintf (NULL, "%s\n", _("memory exhausted"));
3625ba6b03cSchristos # else
3635ba6b03cSchristos fprintf (stderr, "%s\n", _("memory exhausted"));
3645ba6b03cSchristos # endif
3652a6b7db3Sskrll exit (obstack_exit_failure);
3662a6b7db3Sskrll }
3672a6b7db3Sskrll
3685ba6b03cSchristos /* The functions allocating more room by calling 'obstack_chunk_alloc'
3695ba6b03cSchristos jump to the handler pointed to by 'obstack_alloc_failed_handler'.
3705ba6b03cSchristos This can be set to a user defined function which should either
3715ba6b03cSchristos abort gracefully or use longjump - but shouldn't return. This
3725ba6b03cSchristos variable by default points to the internal function
3735ba6b03cSchristos 'print_and_abort'. */
3745ba6b03cSchristos void (*obstack_alloc_failed_handler) (void) = print_and_abort;
3755ba6b03cSchristos # endif /* !_OBSTACK_NO_ERROR_HANDLER */
3765ba6b03cSchristos #endif /* !_OBSTACK_ELIDE_CODE */
377