ralloc.c revision d8407755
1af69d88dSmrg/*
2af69d88dSmrg * Copyright © 2010 Intel Corporation
3af69d88dSmrg *
4af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5af69d88dSmrg * copy of this software and associated documentation files (the "Software"),
6af69d88dSmrg * to deal in the Software without restriction, including without limitation
7af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the
9af69d88dSmrg * Software is furnished to do so, subject to the following conditions:
10af69d88dSmrg *
11af69d88dSmrg * The above copyright notice and this permission notice (including the next
12af69d88dSmrg * paragraph) shall be included in all copies or substantial portions of the
13af69d88dSmrg * Software.
14af69d88dSmrg *
15af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16af69d88dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19af69d88dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20af69d88dSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21af69d88dSmrg * DEALINGS IN THE SOFTWARE.
22af69d88dSmrg */
23af69d88dSmrg
24af69d88dSmrg#include <assert.h>
25af69d88dSmrg#include <stdlib.h>
26af69d88dSmrg#include <stdarg.h>
27af69d88dSmrg#include <stdio.h>
28af69d88dSmrg#include <string.h>
29af69d88dSmrg#include <stdint.h>
30af69d88dSmrg
31af69d88dSmrg/* Some versions of MinGW are missing _vscprintf's declaration, although they
32af69d88dSmrg * still provide the symbol in the import library. */
33af69d88dSmrg#ifdef __MINGW32__
34af69d88dSmrg_CRTIMP int _vscprintf(const char *format, va_list argptr);
35af69d88dSmrg#endif
36af69d88dSmrg
37af69d88dSmrg#include "ralloc.h"
38af69d88dSmrg
39af69d88dSmrg#ifndef va_copy
40af69d88dSmrg#ifdef __va_copy
41af69d88dSmrg#define va_copy(dest, src) __va_copy((dest), (src))
42af69d88dSmrg#else
43af69d88dSmrg#define va_copy(dest, src) (dest) = (src)
44af69d88dSmrg#endif
45af69d88dSmrg#endif
46af69d88dSmrg
47af69d88dSmrg#define CANARY 0x5A1106
48af69d88dSmrg
497e995a2eSmrg/* Align the header's size so that ralloc() allocations will return with the
507e995a2eSmrg * same alignment as a libc malloc would have (8 on 32-bit GLIBC, 16 on
517e995a2eSmrg * 64-bit), avoiding performance penalities on x86 and alignment faults on
527e995a2eSmrg * ARM.
537e995a2eSmrg */
547e995a2eSmrgstruct
557e995a2eSmrg#ifdef _MSC_VER
567e995a2eSmrg __declspec(align(8))
577e995a2eSmrg#elif defined(__LP64__)
587e995a2eSmrg __attribute__((aligned(16)))
597e995a2eSmrg#else
607e995a2eSmrg __attribute__((aligned(8)))
617e995a2eSmrg#endif
627e995a2eSmrg   ralloc_header
63af69d88dSmrg{
64d8407755Smaya#ifndef NDEBUG
65af69d88dSmrg   /* A canary value used to determine whether a pointer is ralloc'd. */
66af69d88dSmrg   unsigned canary;
67af69d88dSmrg#endif
68af69d88dSmrg
69af69d88dSmrg   struct ralloc_header *parent;
70af69d88dSmrg
71af69d88dSmrg   /* The first child (head of a linked list) */
72af69d88dSmrg   struct ralloc_header *child;
73af69d88dSmrg
74af69d88dSmrg   /* Linked list of siblings */
75af69d88dSmrg   struct ralloc_header *prev;
76af69d88dSmrg   struct ralloc_header *next;
77af69d88dSmrg
78af69d88dSmrg   void (*destructor)(void *);
79af69d88dSmrg};
80af69d88dSmrg
81af69d88dSmrgtypedef struct ralloc_header ralloc_header;
82af69d88dSmrg
83af69d88dSmrgstatic void unlink_block(ralloc_header *info);
84af69d88dSmrgstatic void unsafe_free(ralloc_header *info);
85af69d88dSmrg
86af69d88dSmrgstatic ralloc_header *
87af69d88dSmrgget_header(const void *ptr)
88af69d88dSmrg{
89af69d88dSmrg   ralloc_header *info = (ralloc_header *) (((char *) ptr) -
90af69d88dSmrg					    sizeof(ralloc_header));
91af69d88dSmrg   assert(info->canary == CANARY);
92af69d88dSmrg   return info;
93af69d88dSmrg}
94af69d88dSmrg
95af69d88dSmrg#define PTR_FROM_HEADER(info) (((char *) info) + sizeof(ralloc_header))
96af69d88dSmrg
97af69d88dSmrgstatic void
98af69d88dSmrgadd_child(ralloc_header *parent, ralloc_header *info)
99af69d88dSmrg{
100af69d88dSmrg   if (parent != NULL) {
101af69d88dSmrg      info->parent = parent;
102af69d88dSmrg      info->next = parent->child;
103af69d88dSmrg      parent->child = info;
104af69d88dSmrg
105af69d88dSmrg      if (info->next != NULL)
106af69d88dSmrg	 info->next->prev = info;
107af69d88dSmrg   }
108af69d88dSmrg}
109af69d88dSmrg
110af69d88dSmrgvoid *
111af69d88dSmrgralloc_context(const void *ctx)
112af69d88dSmrg{
113af69d88dSmrg   return ralloc_size(ctx, 0);
114af69d88dSmrg}
115af69d88dSmrg
116af69d88dSmrgvoid *
117af69d88dSmrgralloc_size(const void *ctx, size_t size)
118af69d88dSmrg{
1197e995a2eSmrg   void *block = malloc(size + sizeof(ralloc_header));
120af69d88dSmrg   ralloc_header *info;
121af69d88dSmrg   ralloc_header *parent;
122af69d88dSmrg
123af69d88dSmrg   if (unlikely(block == NULL))
124af69d88dSmrg      return NULL;
1257e995a2eSmrg
126af69d88dSmrg   info = (ralloc_header *) block;
1277e995a2eSmrg   /* measurements have shown that calloc is slower (because of
1287e995a2eSmrg    * the multiplication overflow checking?), so clear things
1297e995a2eSmrg    * manually
1307e995a2eSmrg    */
1317e995a2eSmrg   info->parent = NULL;
1327e995a2eSmrg   info->child = NULL;
1337e995a2eSmrg   info->prev = NULL;
1347e995a2eSmrg   info->next = NULL;
1357e995a2eSmrg   info->destructor = NULL;
1367e995a2eSmrg
137af69d88dSmrg   parent = ctx != NULL ? get_header(ctx) : NULL;
138af69d88dSmrg
139af69d88dSmrg   add_child(parent, info);
140af69d88dSmrg
141d8407755Smaya#ifndef NDEBUG
142af69d88dSmrg   info->canary = CANARY;
143af69d88dSmrg#endif
144af69d88dSmrg
145af69d88dSmrg   return PTR_FROM_HEADER(info);
146af69d88dSmrg}
147af69d88dSmrg
148af69d88dSmrgvoid *
149af69d88dSmrgrzalloc_size(const void *ctx, size_t size)
150af69d88dSmrg{
151af69d88dSmrg   void *ptr = ralloc_size(ctx, size);
1527e995a2eSmrg
1537e995a2eSmrg   if (likely(ptr))
154af69d88dSmrg      memset(ptr, 0, size);
1557e995a2eSmrg
156af69d88dSmrg   return ptr;
157af69d88dSmrg}
158af69d88dSmrg
159af69d88dSmrg/* helper function - assumes ptr != NULL */
160af69d88dSmrgstatic void *
161af69d88dSmrgresize(void *ptr, size_t size)
162af69d88dSmrg{
163af69d88dSmrg   ralloc_header *child, *old, *info;
164af69d88dSmrg
165af69d88dSmrg   old = get_header(ptr);
166af69d88dSmrg   info = realloc(old, size + sizeof(ralloc_header));
167af69d88dSmrg
168af69d88dSmrg   if (info == NULL)
169af69d88dSmrg      return NULL;
170af69d88dSmrg
171af69d88dSmrg   /* Update parent and sibling's links to the reallocated node. */
172af69d88dSmrg   if (info != old && info->parent != NULL) {
173af69d88dSmrg      if (info->parent->child == old)
174af69d88dSmrg	 info->parent->child = info;
175af69d88dSmrg
176af69d88dSmrg      if (info->prev != NULL)
177af69d88dSmrg	 info->prev->next = info;
178af69d88dSmrg
179af69d88dSmrg      if (info->next != NULL)
180af69d88dSmrg	 info->next->prev = info;
181af69d88dSmrg   }
182af69d88dSmrg
183af69d88dSmrg   /* Update child->parent links for all children */
184af69d88dSmrg   for (child = info->child; child != NULL; child = child->next)
185af69d88dSmrg      child->parent = info;
186af69d88dSmrg
187af69d88dSmrg   return PTR_FROM_HEADER(info);
188af69d88dSmrg}
189af69d88dSmrg
190af69d88dSmrgvoid *
191af69d88dSmrgreralloc_size(const void *ctx, void *ptr, size_t size)
192af69d88dSmrg{
193af69d88dSmrg   if (unlikely(ptr == NULL))
194af69d88dSmrg      return ralloc_size(ctx, size);
195af69d88dSmrg
196af69d88dSmrg   assert(ralloc_parent(ptr) == ctx);
197af69d88dSmrg   return resize(ptr, size);
198af69d88dSmrg}
199af69d88dSmrg
200af69d88dSmrgvoid *
201af69d88dSmrgralloc_array_size(const void *ctx, size_t size, unsigned count)
202af69d88dSmrg{
203af69d88dSmrg   if (count > SIZE_MAX/size)
204af69d88dSmrg      return NULL;
205af69d88dSmrg
206af69d88dSmrg   return ralloc_size(ctx, size * count);
207af69d88dSmrg}
208af69d88dSmrg
209af69d88dSmrgvoid *
210af69d88dSmrgrzalloc_array_size(const void *ctx, size_t size, unsigned count)
211af69d88dSmrg{
212af69d88dSmrg   if (count > SIZE_MAX/size)
213af69d88dSmrg      return NULL;
214af69d88dSmrg
215af69d88dSmrg   return rzalloc_size(ctx, size * count);
216af69d88dSmrg}
217af69d88dSmrg
218af69d88dSmrgvoid *
219af69d88dSmrgreralloc_array_size(const void *ctx, void *ptr, size_t size, unsigned count)
220af69d88dSmrg{
221af69d88dSmrg   if (count > SIZE_MAX/size)
222af69d88dSmrg      return NULL;
223af69d88dSmrg
224af69d88dSmrg   return reralloc_size(ctx, ptr, size * count);
225af69d88dSmrg}
226af69d88dSmrg
227af69d88dSmrgvoid
228af69d88dSmrgralloc_free(void *ptr)
229af69d88dSmrg{
230af69d88dSmrg   ralloc_header *info;
231af69d88dSmrg
232af69d88dSmrg   if (ptr == NULL)
233af69d88dSmrg      return;
234af69d88dSmrg
235af69d88dSmrg   info = get_header(ptr);
236af69d88dSmrg   unlink_block(info);
237af69d88dSmrg   unsafe_free(info);
238af69d88dSmrg}
239af69d88dSmrg
240af69d88dSmrgstatic void
241af69d88dSmrgunlink_block(ralloc_header *info)
242af69d88dSmrg{
243af69d88dSmrg   /* Unlink from parent & siblings */
244af69d88dSmrg   if (info->parent != NULL) {
245af69d88dSmrg      if (info->parent->child == info)
246af69d88dSmrg	 info->parent->child = info->next;
247af69d88dSmrg
248af69d88dSmrg      if (info->prev != NULL)
249af69d88dSmrg	 info->prev->next = info->next;
250af69d88dSmrg
251af69d88dSmrg      if (info->next != NULL)
252af69d88dSmrg	 info->next->prev = info->prev;
253af69d88dSmrg   }
254af69d88dSmrg   info->parent = NULL;
255af69d88dSmrg   info->prev = NULL;
256af69d88dSmrg   info->next = NULL;
257af69d88dSmrg}
258af69d88dSmrg
259af69d88dSmrgstatic void
260af69d88dSmrgunsafe_free(ralloc_header *info)
261af69d88dSmrg{
262af69d88dSmrg   /* Recursively free any children...don't waste time unlinking them. */
263af69d88dSmrg   ralloc_header *temp;
264af69d88dSmrg   while (info->child != NULL) {
265af69d88dSmrg      temp = info->child;
266af69d88dSmrg      info->child = temp->next;
267af69d88dSmrg      unsafe_free(temp);
268af69d88dSmrg   }
269af69d88dSmrg
270af69d88dSmrg   /* Free the block itself.  Call the destructor first, if any. */
271af69d88dSmrg   if (info->destructor != NULL)
272af69d88dSmrg      info->destructor(PTR_FROM_HEADER(info));
273af69d88dSmrg
274af69d88dSmrg   free(info);
275af69d88dSmrg}
276af69d88dSmrg
277af69d88dSmrgvoid
278af69d88dSmrgralloc_steal(const void *new_ctx, void *ptr)
279af69d88dSmrg{
280af69d88dSmrg   ralloc_header *info, *parent;
281af69d88dSmrg
282af69d88dSmrg   if (unlikely(ptr == NULL))
283af69d88dSmrg      return;
284af69d88dSmrg
285af69d88dSmrg   info = get_header(ptr);
2867e995a2eSmrg   parent = new_ctx ? get_header(new_ctx) : NULL;
287af69d88dSmrg
288af69d88dSmrg   unlink_block(info);
289af69d88dSmrg
290af69d88dSmrg   add_child(parent, info);
291af69d88dSmrg}
292af69d88dSmrg
2937e995a2eSmrgvoid
2947e995a2eSmrgralloc_adopt(const void *new_ctx, void *old_ctx)
2957e995a2eSmrg{
2967e995a2eSmrg   ralloc_header *new_info, *old_info, *child;
2977e995a2eSmrg
2987e995a2eSmrg   if (unlikely(old_ctx == NULL))
2997e995a2eSmrg      return;
3007e995a2eSmrg
3017e995a2eSmrg   old_info = get_header(old_ctx);
3027e995a2eSmrg   new_info = get_header(new_ctx);
3037e995a2eSmrg
3047e995a2eSmrg   /* If there are no children, bail. */
3057e995a2eSmrg   if (unlikely(old_info->child == NULL))
3067e995a2eSmrg      return;
3077e995a2eSmrg
3087e995a2eSmrg   /* Set all the children's parent to new_ctx; get a pointer to the last child. */
3097e995a2eSmrg   for (child = old_info->child; child->next != NULL; child = child->next) {
3107e995a2eSmrg      child->parent = new_info;
3117e995a2eSmrg   }
3127e995a2eSmrg   child->parent = new_info;
3137e995a2eSmrg
3147e995a2eSmrg   /* Connect the two lists together; parent them to new_ctx; make old_ctx empty. */
3157e995a2eSmrg   child->next = new_info->child;
3167e995a2eSmrg   if (child->next)
3177e995a2eSmrg      child->next->prev = child;
3187e995a2eSmrg   new_info->child = old_info->child;
3197e995a2eSmrg   old_info->child = NULL;
3207e995a2eSmrg}
3217e995a2eSmrg
322af69d88dSmrgvoid *
323af69d88dSmrgralloc_parent(const void *ptr)
324af69d88dSmrg{
325af69d88dSmrg   ralloc_header *info;
326af69d88dSmrg
327af69d88dSmrg   if (unlikely(ptr == NULL))
328af69d88dSmrg      return NULL;
329af69d88dSmrg
330af69d88dSmrg   info = get_header(ptr);
331af69d88dSmrg   return info->parent ? PTR_FROM_HEADER(info->parent) : NULL;
332af69d88dSmrg}
333af69d88dSmrg
334af69d88dSmrgvoid
335af69d88dSmrgralloc_set_destructor(const void *ptr, void(*destructor)(void *))
336af69d88dSmrg{
337af69d88dSmrg   ralloc_header *info = get_header(ptr);
338af69d88dSmrg   info->destructor = destructor;
339af69d88dSmrg}
340af69d88dSmrg
341af69d88dSmrgchar *
342af69d88dSmrgralloc_strdup(const void *ctx, const char *str)
343af69d88dSmrg{
344af69d88dSmrg   size_t n;
345af69d88dSmrg   char *ptr;
346af69d88dSmrg
347af69d88dSmrg   if (unlikely(str == NULL))
348af69d88dSmrg      return NULL;
349af69d88dSmrg
350af69d88dSmrg   n = strlen(str);
351af69d88dSmrg   ptr = ralloc_array(ctx, char, n + 1);
352af69d88dSmrg   memcpy(ptr, str, n);
353af69d88dSmrg   ptr[n] = '\0';
354af69d88dSmrg   return ptr;
355af69d88dSmrg}
356af69d88dSmrg
357af69d88dSmrgchar *
358af69d88dSmrgralloc_strndup(const void *ctx, const char *str, size_t max)
359af69d88dSmrg{
360af69d88dSmrg   size_t n;
361af69d88dSmrg   char *ptr;
362af69d88dSmrg
363af69d88dSmrg   if (unlikely(str == NULL))
364af69d88dSmrg      return NULL;
365af69d88dSmrg
3667e995a2eSmrg   n = strnlen(str, max);
367af69d88dSmrg   ptr = ralloc_array(ctx, char, n + 1);
368af69d88dSmrg   memcpy(ptr, str, n);
369af69d88dSmrg   ptr[n] = '\0';
370af69d88dSmrg   return ptr;
371af69d88dSmrg}
372af69d88dSmrg
373af69d88dSmrg/* helper routine for strcat/strncat - n is the exact amount to copy */
374af69d88dSmrgstatic bool
375af69d88dSmrgcat(char **dest, const char *str, size_t n)
376af69d88dSmrg{
377af69d88dSmrg   char *both;
378af69d88dSmrg   size_t existing_length;
379af69d88dSmrg   assert(dest != NULL && *dest != NULL);
380af69d88dSmrg
381af69d88dSmrg   existing_length = strlen(*dest);
382af69d88dSmrg   both = resize(*dest, existing_length + n + 1);
383af69d88dSmrg   if (unlikely(both == NULL))
384af69d88dSmrg      return false;
385af69d88dSmrg
386af69d88dSmrg   memcpy(both + existing_length, str, n);
387af69d88dSmrg   both[existing_length + n] = '\0';
388af69d88dSmrg
389af69d88dSmrg   *dest = both;
390af69d88dSmrg   return true;
391af69d88dSmrg}
392af69d88dSmrg
393af69d88dSmrg
394af69d88dSmrgbool
395af69d88dSmrgralloc_strcat(char **dest, const char *str)
396af69d88dSmrg{
397af69d88dSmrg   return cat(dest, str, strlen(str));
398af69d88dSmrg}
399af69d88dSmrg
400af69d88dSmrgbool
401af69d88dSmrgralloc_strncat(char **dest, const char *str, size_t n)
402af69d88dSmrg{
4037e995a2eSmrg   return cat(dest, str, strnlen(str, n));
4047e995a2eSmrg}
4057e995a2eSmrg
4067e995a2eSmrgbool
4077e995a2eSmrgralloc_str_append(char **dest, const char *str,
4087e995a2eSmrg                  size_t existing_length, size_t str_size)
4097e995a2eSmrg{
4107e995a2eSmrg   char *both;
4117e995a2eSmrg   assert(dest != NULL && *dest != NULL);
4127e995a2eSmrg
4137e995a2eSmrg   both = resize(*dest, existing_length + str_size + 1);
4147e995a2eSmrg   if (unlikely(both == NULL))
4157e995a2eSmrg      return false;
416af69d88dSmrg
4177e995a2eSmrg   memcpy(both + existing_length, str, str_size);
4187e995a2eSmrg   both[existing_length + str_size] = '\0';
4197e995a2eSmrg
4207e995a2eSmrg   *dest = both;
4217e995a2eSmrg
4227e995a2eSmrg   return true;
423af69d88dSmrg}
424af69d88dSmrg
425af69d88dSmrgchar *
426af69d88dSmrgralloc_asprintf(const void *ctx, const char *fmt, ...)
427af69d88dSmrg{
428af69d88dSmrg   char *ptr;
429af69d88dSmrg   va_list args;
430af69d88dSmrg   va_start(args, fmt);
431af69d88dSmrg   ptr = ralloc_vasprintf(ctx, fmt, args);
432af69d88dSmrg   va_end(args);
433af69d88dSmrg   return ptr;
434af69d88dSmrg}
435af69d88dSmrg
436af69d88dSmrg/* Return the length of the string that would be generated by a printf-style
437af69d88dSmrg * format and argument list, not including the \0 byte.
438af69d88dSmrg */
439af69d88dSmrgstatic size_t
440af69d88dSmrgprintf_length(const char *fmt, va_list untouched_args)
441af69d88dSmrg{
442af69d88dSmrg   int size;
443af69d88dSmrg   char junk;
444af69d88dSmrg
445af69d88dSmrg   /* Make a copy of the va_list so the original caller can still use it */
446af69d88dSmrg   va_list args;
447af69d88dSmrg   va_copy(args, untouched_args);
448af69d88dSmrg
449af69d88dSmrg#ifdef _WIN32
450af69d88dSmrg   /* We need to use _vcsprintf to calculate the size as vsnprintf returns -1
451af69d88dSmrg    * if the number of characters to write is greater than count.
452af69d88dSmrg    */
453af69d88dSmrg   size = _vscprintf(fmt, args);
454af69d88dSmrg   (void)junk;
455af69d88dSmrg#else
456af69d88dSmrg   size = vsnprintf(&junk, 1, fmt, args);
457af69d88dSmrg#endif
458af69d88dSmrg   assert(size >= 0);
459af69d88dSmrg
460af69d88dSmrg   va_end(args);
461af69d88dSmrg
462af69d88dSmrg   return size;
463af69d88dSmrg}
464af69d88dSmrg
465af69d88dSmrgchar *
466af69d88dSmrgralloc_vasprintf(const void *ctx, const char *fmt, va_list args)
467af69d88dSmrg{
468af69d88dSmrg   size_t size = printf_length(fmt, args) + 1;
469af69d88dSmrg
470af69d88dSmrg   char *ptr = ralloc_size(ctx, size);
471af69d88dSmrg   if (ptr != NULL)
472af69d88dSmrg      vsnprintf(ptr, size, fmt, args);
473af69d88dSmrg
474af69d88dSmrg   return ptr;
475af69d88dSmrg}
476af69d88dSmrg
477af69d88dSmrgbool
478af69d88dSmrgralloc_asprintf_append(char **str, const char *fmt, ...)
479af69d88dSmrg{
480af69d88dSmrg   bool success;
481af69d88dSmrg   va_list args;
482af69d88dSmrg   va_start(args, fmt);
483af69d88dSmrg   success = ralloc_vasprintf_append(str, fmt, args);
484af69d88dSmrg   va_end(args);
485af69d88dSmrg   return success;
486af69d88dSmrg}
487af69d88dSmrg
488af69d88dSmrgbool
489af69d88dSmrgralloc_vasprintf_append(char **str, const char *fmt, va_list args)
490af69d88dSmrg{
491af69d88dSmrg   size_t existing_length;
492af69d88dSmrg   assert(str != NULL);
493af69d88dSmrg   existing_length = *str ? strlen(*str) : 0;
494af69d88dSmrg   return ralloc_vasprintf_rewrite_tail(str, &existing_length, fmt, args);
495af69d88dSmrg}
496af69d88dSmrg
497af69d88dSmrgbool
498af69d88dSmrgralloc_asprintf_rewrite_tail(char **str, size_t *start, const char *fmt, ...)
499af69d88dSmrg{
500af69d88dSmrg   bool success;
501af69d88dSmrg   va_list args;
502af69d88dSmrg   va_start(args, fmt);
503af69d88dSmrg   success = ralloc_vasprintf_rewrite_tail(str, start, fmt, args);
504af69d88dSmrg   va_end(args);
505af69d88dSmrg   return success;
506af69d88dSmrg}
507af69d88dSmrg
508af69d88dSmrgbool
509af69d88dSmrgralloc_vasprintf_rewrite_tail(char **str, size_t *start, const char *fmt,
510af69d88dSmrg			      va_list args)
511af69d88dSmrg{
512af69d88dSmrg   size_t new_length;
513af69d88dSmrg   char *ptr;
514af69d88dSmrg
515af69d88dSmrg   assert(str != NULL);
516af69d88dSmrg
517af69d88dSmrg   if (unlikely(*str == NULL)) {
518af69d88dSmrg      // Assuming a NULL context is probably bad, but it's expected behavior.
519af69d88dSmrg      *str = ralloc_vasprintf(NULL, fmt, args);
5207e995a2eSmrg      *start = strlen(*str);
521af69d88dSmrg      return true;
522af69d88dSmrg   }
523af69d88dSmrg
524af69d88dSmrg   new_length = printf_length(fmt, args);
525af69d88dSmrg
526af69d88dSmrg   ptr = resize(*str, *start + new_length + 1);
527af69d88dSmrg   if (unlikely(ptr == NULL))
528af69d88dSmrg      return false;
529af69d88dSmrg
530af69d88dSmrg   vsnprintf(ptr + *start, new_length + 1, fmt, args);
531af69d88dSmrg   *str = ptr;
532af69d88dSmrg   *start += new_length;
533af69d88dSmrg   return true;
534af69d88dSmrg}
5357e995a2eSmrg
5367e995a2eSmrg/***************************************************************************
5377e995a2eSmrg * Linear allocator for short-lived allocations.
5387e995a2eSmrg ***************************************************************************
5397e995a2eSmrg *
5407e995a2eSmrg * The allocator consists of a parent node (2K buffer), which requires
5417e995a2eSmrg * a ralloc parent, and child nodes (allocations). Child nodes can't be freed
5427e995a2eSmrg * directly, because the parent doesn't track them. You have to release
5437e995a2eSmrg * the parent node in order to release all its children.
5447e995a2eSmrg *
5457e995a2eSmrg * The allocator uses a fixed-sized buffer with a monotonically increasing
5467e995a2eSmrg * offset after each allocation. If the buffer is all used, another buffer
5477e995a2eSmrg * is allocated, sharing the same ralloc parent, so all buffers are at
5487e995a2eSmrg * the same level in the ralloc hierarchy.
5497e995a2eSmrg *
5507e995a2eSmrg * The linear parent node is always the first buffer and keeps track of all
5517e995a2eSmrg * other buffers.
5527e995a2eSmrg */
5537e995a2eSmrg
5547e995a2eSmrg#define MIN_LINEAR_BUFSIZE 2048
5557e995a2eSmrg#define SUBALLOC_ALIGNMENT 8
5567e995a2eSmrg#define LMAGIC 0x87b9c7d3
5577e995a2eSmrg
5587e995a2eSmrgstruct
5597e995a2eSmrg#ifdef _MSC_VER
5607e995a2eSmrg __declspec(align(8))
5617e995a2eSmrg#elif defined(__LP64__)
5627e995a2eSmrg __attribute__((aligned(16)))
5637e995a2eSmrg#else
5647e995a2eSmrg __attribute__((aligned(8)))
5657e995a2eSmrg#endif
5667e995a2eSmrg   linear_header {
567d8407755Smaya#ifndef NDEBUG
5687e995a2eSmrg   unsigned magic;   /* for debugging */
5697e995a2eSmrg#endif
5707e995a2eSmrg   unsigned offset;  /* points to the first unused byte in the buffer */
5717e995a2eSmrg   unsigned size;    /* size of the buffer */
5727e995a2eSmrg   void *ralloc_parent;          /* new buffers will use this */
5737e995a2eSmrg   struct linear_header *next;   /* next buffer if we have more */
5747e995a2eSmrg   struct linear_header *latest; /* the only buffer that has free space */
5757e995a2eSmrg
5767e995a2eSmrg   /* After this structure, the buffer begins.
5777e995a2eSmrg    * Each suballocation consists of linear_size_chunk as its header followed
5787e995a2eSmrg    * by the suballocation, so it goes:
5797e995a2eSmrg    *
5807e995a2eSmrg    * - linear_size_chunk
5817e995a2eSmrg    * - allocated space
5827e995a2eSmrg    * - linear_size_chunk
5837e995a2eSmrg    * - allocated space
5847e995a2eSmrg    * etc.
5857e995a2eSmrg    *
5867e995a2eSmrg    * linear_size_chunk is only needed by linear_realloc.
5877e995a2eSmrg    */
5887e995a2eSmrg};
5897e995a2eSmrg
5907e995a2eSmrgstruct linear_size_chunk {
5917e995a2eSmrg   unsigned size; /* for realloc */
5927e995a2eSmrg   unsigned _padding;
5937e995a2eSmrg};
5947e995a2eSmrg
5957e995a2eSmrgtypedef struct linear_header linear_header;
5967e995a2eSmrgtypedef struct linear_size_chunk linear_size_chunk;
5977e995a2eSmrg
5987e995a2eSmrg#define LINEAR_PARENT_TO_HEADER(parent) \
5997e995a2eSmrg   (linear_header*) \
6007e995a2eSmrg   ((char*)(parent) - sizeof(linear_size_chunk) - sizeof(linear_header))
6017e995a2eSmrg
6027e995a2eSmrg/* Allocate the linear buffer with its header. */
6037e995a2eSmrgstatic linear_header *
6047e995a2eSmrgcreate_linear_node(void *ralloc_ctx, unsigned min_size)
6057e995a2eSmrg{
6067e995a2eSmrg   linear_header *node;
6077e995a2eSmrg
6087e995a2eSmrg   min_size += sizeof(linear_size_chunk);
6097e995a2eSmrg
6107e995a2eSmrg   if (likely(min_size < MIN_LINEAR_BUFSIZE))
6117e995a2eSmrg      min_size = MIN_LINEAR_BUFSIZE;
6127e995a2eSmrg
6137e995a2eSmrg   node = ralloc_size(ralloc_ctx, sizeof(linear_header) + min_size);
6147e995a2eSmrg   if (unlikely(!node))
6157e995a2eSmrg      return NULL;
6167e995a2eSmrg
617d8407755Smaya#ifndef NDEBUG
6187e995a2eSmrg   node->magic = LMAGIC;
6197e995a2eSmrg#endif
6207e995a2eSmrg   node->offset = 0;
6217e995a2eSmrg   node->size = min_size;
6227e995a2eSmrg   node->ralloc_parent = ralloc_ctx;
6237e995a2eSmrg   node->next = NULL;
6247e995a2eSmrg   node->latest = node;
6257e995a2eSmrg   return node;
6267e995a2eSmrg}
6277e995a2eSmrg
6287e995a2eSmrgvoid *
6297e995a2eSmrglinear_alloc_child(void *parent, unsigned size)
6307e995a2eSmrg{
6317e995a2eSmrg   linear_header *first = LINEAR_PARENT_TO_HEADER(parent);
6327e995a2eSmrg   linear_header *latest = first->latest;
6337e995a2eSmrg   linear_header *new_node;
6347e995a2eSmrg   linear_size_chunk *ptr;
6357e995a2eSmrg   unsigned full_size;
6367e995a2eSmrg
6377e995a2eSmrg   assert(first->magic == LMAGIC);
6387e995a2eSmrg   assert(!latest->next);
6397e995a2eSmrg
6407e995a2eSmrg   size = ALIGN_POT(size, SUBALLOC_ALIGNMENT);
6417e995a2eSmrg   full_size = sizeof(linear_size_chunk) + size;
6427e995a2eSmrg
6437e995a2eSmrg   if (unlikely(latest->offset + full_size > latest->size)) {
6447e995a2eSmrg      /* allocate a new node */
6457e995a2eSmrg      new_node = create_linear_node(latest->ralloc_parent, size);
6467e995a2eSmrg      if (unlikely(!new_node))
6477e995a2eSmrg         return NULL;
6487e995a2eSmrg
6497e995a2eSmrg      first->latest = new_node;
6507e995a2eSmrg      latest->latest = new_node;
6517e995a2eSmrg      latest->next = new_node;
6527e995a2eSmrg      latest = new_node;
6537e995a2eSmrg   }
6547e995a2eSmrg
6557e995a2eSmrg   ptr = (linear_size_chunk *)((char*)&latest[1] + latest->offset);
6567e995a2eSmrg   ptr->size = size;
6577e995a2eSmrg   latest->offset += full_size;
6587e995a2eSmrg
6597e995a2eSmrg   assert((uintptr_t)&ptr[1] % SUBALLOC_ALIGNMENT == 0);
6607e995a2eSmrg   return &ptr[1];
6617e995a2eSmrg}
6627e995a2eSmrg
6637e995a2eSmrgvoid *
6647e995a2eSmrglinear_alloc_parent(void *ralloc_ctx, unsigned size)
6657e995a2eSmrg{
6667e995a2eSmrg   linear_header *node;
6677e995a2eSmrg
6687e995a2eSmrg   if (unlikely(!ralloc_ctx))
6697e995a2eSmrg      return NULL;
6707e995a2eSmrg
6717e995a2eSmrg   size = ALIGN_POT(size, SUBALLOC_ALIGNMENT);
6727e995a2eSmrg
6737e995a2eSmrg   node = create_linear_node(ralloc_ctx, size);
6747e995a2eSmrg   if (unlikely(!node))
6757e995a2eSmrg      return NULL;
6767e995a2eSmrg
6777e995a2eSmrg   return linear_alloc_child((char*)node +
6787e995a2eSmrg                             sizeof(linear_header) +
6797e995a2eSmrg                             sizeof(linear_size_chunk), size);
6807e995a2eSmrg}
6817e995a2eSmrg
6827e995a2eSmrgvoid *
6837e995a2eSmrglinear_zalloc_child(void *parent, unsigned size)
6847e995a2eSmrg{
6857e995a2eSmrg   void *ptr = linear_alloc_child(parent, size);
6867e995a2eSmrg
6877e995a2eSmrg   if (likely(ptr))
6887e995a2eSmrg      memset(ptr, 0, size);
6897e995a2eSmrg   return ptr;
6907e995a2eSmrg}
6917e995a2eSmrg
6927e995a2eSmrgvoid *
6937e995a2eSmrglinear_zalloc_parent(void *parent, unsigned size)
6947e995a2eSmrg{
6957e995a2eSmrg   void *ptr = linear_alloc_parent(parent, size);
6967e995a2eSmrg
6977e995a2eSmrg   if (likely(ptr))
6987e995a2eSmrg      memset(ptr, 0, size);
6997e995a2eSmrg   return ptr;
7007e995a2eSmrg}
7017e995a2eSmrg
7027e995a2eSmrgvoid
7037e995a2eSmrglinear_free_parent(void *ptr)
7047e995a2eSmrg{
7057e995a2eSmrg   linear_header *node;
7067e995a2eSmrg
7077e995a2eSmrg   if (unlikely(!ptr))
7087e995a2eSmrg      return;
7097e995a2eSmrg
7107e995a2eSmrg   node = LINEAR_PARENT_TO_HEADER(ptr);
7117e995a2eSmrg   assert(node->magic == LMAGIC);
7127e995a2eSmrg
7137e995a2eSmrg   while (node) {
7147e995a2eSmrg      void *ptr = node;
7157e995a2eSmrg
7167e995a2eSmrg      node = node->next;
7177e995a2eSmrg      ralloc_free(ptr);
7187e995a2eSmrg   }
7197e995a2eSmrg}
7207e995a2eSmrg
7217e995a2eSmrgvoid
7227e995a2eSmrgralloc_steal_linear_parent(void *new_ralloc_ctx, void *ptr)
7237e995a2eSmrg{
7247e995a2eSmrg   linear_header *node;
7257e995a2eSmrg
7267e995a2eSmrg   if (unlikely(!ptr))
7277e995a2eSmrg      return;
7287e995a2eSmrg
7297e995a2eSmrg   node = LINEAR_PARENT_TO_HEADER(ptr);
7307e995a2eSmrg   assert(node->magic == LMAGIC);
7317e995a2eSmrg
7327e995a2eSmrg   while (node) {
7337e995a2eSmrg      ralloc_steal(new_ralloc_ctx, node);
7347e995a2eSmrg      node->ralloc_parent = new_ralloc_ctx;
7357e995a2eSmrg      node = node->next;
7367e995a2eSmrg   }
7377e995a2eSmrg}
7387e995a2eSmrg
7397e995a2eSmrgvoid *
7407e995a2eSmrgralloc_parent_of_linear_parent(void *ptr)
7417e995a2eSmrg{
7427e995a2eSmrg   linear_header *node = LINEAR_PARENT_TO_HEADER(ptr);
7437e995a2eSmrg   assert(node->magic == LMAGIC);
7447e995a2eSmrg   return node->ralloc_parent;
7457e995a2eSmrg}
7467e995a2eSmrg
7477e995a2eSmrgvoid *
7487e995a2eSmrglinear_realloc(void *parent, void *old, unsigned new_size)
7497e995a2eSmrg{
7507e995a2eSmrg   unsigned old_size = 0;
7517e995a2eSmrg   ralloc_header *new_ptr;
7527e995a2eSmrg
7537e995a2eSmrg   new_ptr = linear_alloc_child(parent, new_size);
7547e995a2eSmrg
7557e995a2eSmrg   if (unlikely(!old))
7567e995a2eSmrg      return new_ptr;
7577e995a2eSmrg
7587e995a2eSmrg   old_size = ((linear_size_chunk*)old)[-1].size;
7597e995a2eSmrg
7607e995a2eSmrg   if (likely(new_ptr && old_size))
7617e995a2eSmrg      memcpy(new_ptr, old, MIN2(old_size, new_size));
7627e995a2eSmrg
7637e995a2eSmrg   return new_ptr;
7647e995a2eSmrg}
7657e995a2eSmrg
7667e995a2eSmrg/* All code below is pretty much copied from ralloc and only the alloc
7677e995a2eSmrg * calls are different.
7687e995a2eSmrg */
7697e995a2eSmrg
7707e995a2eSmrgchar *
7717e995a2eSmrglinear_strdup(void *parent, const char *str)
7727e995a2eSmrg{
7737e995a2eSmrg   unsigned n;
7747e995a2eSmrg   char *ptr;
7757e995a2eSmrg
7767e995a2eSmrg   if (unlikely(!str))
7777e995a2eSmrg      return NULL;
7787e995a2eSmrg
7797e995a2eSmrg   n = strlen(str);
7807e995a2eSmrg   ptr = linear_alloc_child(parent, n + 1);
7817e995a2eSmrg   if (unlikely(!ptr))
7827e995a2eSmrg      return NULL;
7837e995a2eSmrg
7847e995a2eSmrg   memcpy(ptr, str, n);
7857e995a2eSmrg   ptr[n] = '\0';
7867e995a2eSmrg   return ptr;
7877e995a2eSmrg}
7887e995a2eSmrg
7897e995a2eSmrgchar *
7907e995a2eSmrglinear_asprintf(void *parent, const char *fmt, ...)
7917e995a2eSmrg{
7927e995a2eSmrg   char *ptr;
7937e995a2eSmrg   va_list args;
7947e995a2eSmrg   va_start(args, fmt);
7957e995a2eSmrg   ptr = linear_vasprintf(parent, fmt, args);
7967e995a2eSmrg   va_end(args);
7977e995a2eSmrg   return ptr;
7987e995a2eSmrg}
7997e995a2eSmrg
8007e995a2eSmrgchar *
8017e995a2eSmrglinear_vasprintf(void *parent, const char *fmt, va_list args)
8027e995a2eSmrg{
8037e995a2eSmrg   unsigned size = printf_length(fmt, args) + 1;
8047e995a2eSmrg
8057e995a2eSmrg   char *ptr = linear_alloc_child(parent, size);
8067e995a2eSmrg   if (ptr != NULL)
8077e995a2eSmrg      vsnprintf(ptr, size, fmt, args);
8087e995a2eSmrg
8097e995a2eSmrg   return ptr;
8107e995a2eSmrg}
8117e995a2eSmrg
8127e995a2eSmrgbool
8137e995a2eSmrglinear_asprintf_append(void *parent, char **str, const char *fmt, ...)
8147e995a2eSmrg{
8157e995a2eSmrg   bool success;
8167e995a2eSmrg   va_list args;
8177e995a2eSmrg   va_start(args, fmt);
8187e995a2eSmrg   success = linear_vasprintf_append(parent, str, fmt, args);
8197e995a2eSmrg   va_end(args);
8207e995a2eSmrg   return success;
8217e995a2eSmrg}
8227e995a2eSmrg
8237e995a2eSmrgbool
8247e995a2eSmrglinear_vasprintf_append(void *parent, char **str, const char *fmt, va_list args)
8257e995a2eSmrg{
8267e995a2eSmrg   size_t existing_length;
8277e995a2eSmrg   assert(str != NULL);
8287e995a2eSmrg   existing_length = *str ? strlen(*str) : 0;
8297e995a2eSmrg   return linear_vasprintf_rewrite_tail(parent, str, &existing_length, fmt, args);
8307e995a2eSmrg}
8317e995a2eSmrg
8327e995a2eSmrgbool
8337e995a2eSmrglinear_asprintf_rewrite_tail(void *parent, char **str, size_t *start,
8347e995a2eSmrg                             const char *fmt, ...)
8357e995a2eSmrg{
8367e995a2eSmrg   bool success;
8377e995a2eSmrg   va_list args;
8387e995a2eSmrg   va_start(args, fmt);
8397e995a2eSmrg   success = linear_vasprintf_rewrite_tail(parent, str, start, fmt, args);
8407e995a2eSmrg   va_end(args);
8417e995a2eSmrg   return success;
8427e995a2eSmrg}
8437e995a2eSmrg
8447e995a2eSmrgbool
8457e995a2eSmrglinear_vasprintf_rewrite_tail(void *parent, char **str, size_t *start,
8467e995a2eSmrg                              const char *fmt, va_list args)
8477e995a2eSmrg{
8487e995a2eSmrg   size_t new_length;
8497e995a2eSmrg   char *ptr;
8507e995a2eSmrg
8517e995a2eSmrg   assert(str != NULL);
8527e995a2eSmrg
8537e995a2eSmrg   if (unlikely(*str == NULL)) {
8547e995a2eSmrg      *str = linear_vasprintf(parent, fmt, args);
8557e995a2eSmrg      *start = strlen(*str);
8567e995a2eSmrg      return true;
8577e995a2eSmrg   }
8587e995a2eSmrg
8597e995a2eSmrg   new_length = printf_length(fmt, args);
8607e995a2eSmrg
8617e995a2eSmrg   ptr = linear_realloc(parent, *str, *start + new_length + 1);
8627e995a2eSmrg   if (unlikely(ptr == NULL))
8637e995a2eSmrg      return false;
8647e995a2eSmrg
8657e995a2eSmrg   vsnprintf(ptr + *start, new_length + 1, fmt, args);
8667e995a2eSmrg   *str = ptr;
8677e995a2eSmrg   *start += new_length;
8687e995a2eSmrg   return true;
8697e995a2eSmrg}
8707e995a2eSmrg
8717e995a2eSmrg/* helper routine for strcat/strncat - n is the exact amount to copy */
8727e995a2eSmrgstatic bool
8737e995a2eSmrglinear_cat(void *parent, char **dest, const char *str, unsigned n)
8747e995a2eSmrg{
8757e995a2eSmrg   char *both;
8767e995a2eSmrg   unsigned existing_length;
8777e995a2eSmrg   assert(dest != NULL && *dest != NULL);
8787e995a2eSmrg
8797e995a2eSmrg   existing_length = strlen(*dest);
8807e995a2eSmrg   both = linear_realloc(parent, *dest, existing_length + n + 1);
8817e995a2eSmrg   if (unlikely(both == NULL))
8827e995a2eSmrg      return false;
8837e995a2eSmrg
8847e995a2eSmrg   memcpy(both + existing_length, str, n);
8857e995a2eSmrg   both[existing_length + n] = '\0';
8867e995a2eSmrg
8877e995a2eSmrg   *dest = both;
8887e995a2eSmrg   return true;
8897e995a2eSmrg}
8907e995a2eSmrg
8917e995a2eSmrgbool
8927e995a2eSmrglinear_strcat(void *parent, char **dest, const char *str)
8937e995a2eSmrg{
8947e995a2eSmrg   return linear_cat(parent, dest, str, strlen(str));
8957e995a2eSmrg}
896