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
311463c08dSmrg#include "util/macros.h"
321463c08dSmrg#include "util/u_math.h"
331463c08dSmrg#include "util/u_printf.h"
34af69d88dSmrg
35af69d88dSmrg#include "ralloc.h"
36af69d88dSmrg
37af69d88dSmrg#define CANARY 0x5A1106
38af69d88dSmrg
397e995a2eSmrg/* Align the header's size so that ralloc() allocations will return with the
407e995a2eSmrg * same alignment as a libc malloc would have (8 on 32-bit GLIBC, 16 on
417e995a2eSmrg * 64-bit), avoiding performance penalities on x86 and alignment faults on
427e995a2eSmrg * ARM.
437e995a2eSmrg */
447e995a2eSmrgstruct
457e995a2eSmrg#ifdef _MSC_VER
461463c08dSmrg#if _WIN64
471463c08dSmrg__declspec(align(16))
481463c08dSmrg#else
497e995a2eSmrg __declspec(align(8))
501463c08dSmrg#endif
517e995a2eSmrg#elif defined(__LP64__)
527e995a2eSmrg __attribute__((aligned(16)))
537e995a2eSmrg#else
547e995a2eSmrg __attribute__((aligned(8)))
557e995a2eSmrg#endif
567e995a2eSmrg   ralloc_header
57af69d88dSmrg{
58d8407755Smaya#ifndef NDEBUG
59af69d88dSmrg   /* A canary value used to determine whether a pointer is ralloc'd. */
60af69d88dSmrg   unsigned canary;
61af69d88dSmrg#endif
62af69d88dSmrg
63af69d88dSmrg   struct ralloc_header *parent;
64af69d88dSmrg
65af69d88dSmrg   /* The first child (head of a linked list) */
66af69d88dSmrg   struct ralloc_header *child;
67af69d88dSmrg
68af69d88dSmrg   /* Linked list of siblings */
69af69d88dSmrg   struct ralloc_header *prev;
70af69d88dSmrg   struct ralloc_header *next;
71af69d88dSmrg
72af69d88dSmrg   void (*destructor)(void *);
73af69d88dSmrg};
74af69d88dSmrg
75af69d88dSmrgtypedef struct ralloc_header ralloc_header;
76af69d88dSmrg
77af69d88dSmrgstatic void unlink_block(ralloc_header *info);
78af69d88dSmrgstatic void unsafe_free(ralloc_header *info);
79af69d88dSmrg
80af69d88dSmrgstatic ralloc_header *
81af69d88dSmrgget_header(const void *ptr)
82af69d88dSmrg{
83af69d88dSmrg   ralloc_header *info = (ralloc_header *) (((char *) ptr) -
84af69d88dSmrg					    sizeof(ralloc_header));
85af69d88dSmrg   assert(info->canary == CANARY);
86af69d88dSmrg   return info;
87af69d88dSmrg}
88af69d88dSmrg
89af69d88dSmrg#define PTR_FROM_HEADER(info) (((char *) info) + sizeof(ralloc_header))
90af69d88dSmrg
91af69d88dSmrgstatic void
92af69d88dSmrgadd_child(ralloc_header *parent, ralloc_header *info)
93af69d88dSmrg{
94af69d88dSmrg   if (parent != NULL) {
95af69d88dSmrg      info->parent = parent;
96af69d88dSmrg      info->next = parent->child;
97af69d88dSmrg      parent->child = info;
98af69d88dSmrg
99af69d88dSmrg      if (info->next != NULL)
100af69d88dSmrg	 info->next->prev = info;
101af69d88dSmrg   }
102af69d88dSmrg}
103af69d88dSmrg
104af69d88dSmrgvoid *
105af69d88dSmrgralloc_context(const void *ctx)
106af69d88dSmrg{
107af69d88dSmrg   return ralloc_size(ctx, 0);
108af69d88dSmrg}
109af69d88dSmrg
110af69d88dSmrgvoid *
111af69d88dSmrgralloc_size(const void *ctx, size_t size)
112af69d88dSmrg{
1131463c08dSmrg   /* Some malloc allocation doesn't always align to 16 bytes even on 64 bits
1141463c08dSmrg    * system, from Android bionic/tests/malloc_test.cpp:
1151463c08dSmrg    *  - Allocations of a size that rounds up to a multiple of 16 bytes
1161463c08dSmrg    *    must have at least 16 byte alignment.
1171463c08dSmrg    *  - Allocations of a size that rounds up to a multiple of 8 bytes and
1181463c08dSmrg    *    not 16 bytes, are only required to have at least 8 byte alignment.
1191463c08dSmrg    */
1201463c08dSmrg   void *block = malloc(align64(size + sizeof(ralloc_header),
1211463c08dSmrg                                alignof(ralloc_header)));
122af69d88dSmrg   ralloc_header *info;
123af69d88dSmrg   ralloc_header *parent;
124af69d88dSmrg
125af69d88dSmrg   if (unlikely(block == NULL))
126af69d88dSmrg      return NULL;
1277e995a2eSmrg
128af69d88dSmrg   info = (ralloc_header *) block;
1297e995a2eSmrg   /* measurements have shown that calloc is slower (because of
1307e995a2eSmrg    * the multiplication overflow checking?), so clear things
1317e995a2eSmrg    * manually
1327e995a2eSmrg    */
1337e995a2eSmrg   info->parent = NULL;
1347e995a2eSmrg   info->child = NULL;
1357e995a2eSmrg   info->prev = NULL;
1367e995a2eSmrg   info->next = NULL;
1377e995a2eSmrg   info->destructor = NULL;
1387e995a2eSmrg
139af69d88dSmrg   parent = ctx != NULL ? get_header(ctx) : NULL;
140af69d88dSmrg
141af69d88dSmrg   add_child(parent, info);
142af69d88dSmrg
143d8407755Smaya#ifndef NDEBUG
144af69d88dSmrg   info->canary = CANARY;
145af69d88dSmrg#endif
146af69d88dSmrg
147af69d88dSmrg   return PTR_FROM_HEADER(info);
148af69d88dSmrg}
149af69d88dSmrg
150af69d88dSmrgvoid *
151af69d88dSmrgrzalloc_size(const void *ctx, size_t size)
152af69d88dSmrg{
153af69d88dSmrg   void *ptr = ralloc_size(ctx, size);
1547e995a2eSmrg
1557e995a2eSmrg   if (likely(ptr))
156af69d88dSmrg      memset(ptr, 0, size);
1577e995a2eSmrg
158af69d88dSmrg   return ptr;
159af69d88dSmrg}
160af69d88dSmrg
161af69d88dSmrg/* helper function - assumes ptr != NULL */
162af69d88dSmrgstatic void *
163af69d88dSmrgresize(void *ptr, size_t size)
164af69d88dSmrg{
165af69d88dSmrg   ralloc_header *child, *old, *info;
166af69d88dSmrg
167af69d88dSmrg   old = get_header(ptr);
1681463c08dSmrg   info = realloc(old, align64(size + sizeof(ralloc_header),
1691463c08dSmrg                               alignof(ralloc_header)));
170af69d88dSmrg
171af69d88dSmrg   if (info == NULL)
172af69d88dSmrg      return NULL;
173af69d88dSmrg
174af69d88dSmrg   /* Update parent and sibling's links to the reallocated node. */
175af69d88dSmrg   if (info != old && info->parent != NULL) {
176af69d88dSmrg      if (info->parent->child == old)
177af69d88dSmrg	 info->parent->child = info;
178af69d88dSmrg
179af69d88dSmrg      if (info->prev != NULL)
180af69d88dSmrg	 info->prev->next = info;
181af69d88dSmrg
182af69d88dSmrg      if (info->next != NULL)
183af69d88dSmrg	 info->next->prev = info;
184af69d88dSmrg   }
185af69d88dSmrg
186af69d88dSmrg   /* Update child->parent links for all children */
187af69d88dSmrg   for (child = info->child; child != NULL; child = child->next)
188af69d88dSmrg      child->parent = info;
189af69d88dSmrg
190af69d88dSmrg   return PTR_FROM_HEADER(info);
191af69d88dSmrg}
192af69d88dSmrg
193af69d88dSmrgvoid *
194af69d88dSmrgreralloc_size(const void *ctx, void *ptr, size_t size)
195af69d88dSmrg{
196af69d88dSmrg   if (unlikely(ptr == NULL))
197af69d88dSmrg      return ralloc_size(ctx, size);
198af69d88dSmrg
199af69d88dSmrg   assert(ralloc_parent(ptr) == ctx);
200af69d88dSmrg   return resize(ptr, size);
201af69d88dSmrg}
202af69d88dSmrg
2031463c08dSmrgvoid *
2041463c08dSmrgrerzalloc_size(const void *ctx, void *ptr, size_t old_size, size_t new_size)
2051463c08dSmrg{
2061463c08dSmrg   if (unlikely(ptr == NULL))
2071463c08dSmrg      return rzalloc_size(ctx, new_size);
2081463c08dSmrg
2091463c08dSmrg   assert(ralloc_parent(ptr) == ctx);
2101463c08dSmrg   ptr = resize(ptr, new_size);
2111463c08dSmrg
2121463c08dSmrg   if (new_size > old_size)
2131463c08dSmrg      memset((char *)ptr + old_size, 0, new_size - old_size);
2141463c08dSmrg
2151463c08dSmrg   return ptr;
2161463c08dSmrg}
2171463c08dSmrg
218af69d88dSmrgvoid *
219af69d88dSmrgralloc_array_size(const void *ctx, size_t size, unsigned count)
220af69d88dSmrg{
221af69d88dSmrg   if (count > SIZE_MAX/size)
222af69d88dSmrg      return NULL;
223af69d88dSmrg
224af69d88dSmrg   return ralloc_size(ctx, size * count);
225af69d88dSmrg}
226af69d88dSmrg
227af69d88dSmrgvoid *
228af69d88dSmrgrzalloc_array_size(const void *ctx, size_t size, unsigned count)
229af69d88dSmrg{
230af69d88dSmrg   if (count > SIZE_MAX/size)
231af69d88dSmrg      return NULL;
232af69d88dSmrg
233af69d88dSmrg   return rzalloc_size(ctx, size * count);
234af69d88dSmrg}
235af69d88dSmrg
236af69d88dSmrgvoid *
237af69d88dSmrgreralloc_array_size(const void *ctx, void *ptr, size_t size, unsigned count)
238af69d88dSmrg{
239af69d88dSmrg   if (count > SIZE_MAX/size)
240af69d88dSmrg      return NULL;
241af69d88dSmrg
242af69d88dSmrg   return reralloc_size(ctx, ptr, size * count);
243af69d88dSmrg}
244af69d88dSmrg
2451463c08dSmrgvoid *
2461463c08dSmrgrerzalloc_array_size(const void *ctx, void *ptr, size_t size,
2471463c08dSmrg                     unsigned old_count, unsigned new_count)
2481463c08dSmrg{
2491463c08dSmrg   if (new_count > SIZE_MAX/size)
2501463c08dSmrg      return NULL;
2511463c08dSmrg
2521463c08dSmrg   return rerzalloc_size(ctx, ptr, size * old_count, size * new_count);
2531463c08dSmrg}
2541463c08dSmrg
255af69d88dSmrgvoid
256af69d88dSmrgralloc_free(void *ptr)
257af69d88dSmrg{
258af69d88dSmrg   ralloc_header *info;
259af69d88dSmrg
260af69d88dSmrg   if (ptr == NULL)
261af69d88dSmrg      return;
262af69d88dSmrg
263af69d88dSmrg   info = get_header(ptr);
264af69d88dSmrg   unlink_block(info);
265af69d88dSmrg   unsafe_free(info);
266af69d88dSmrg}
267af69d88dSmrg
268af69d88dSmrgstatic void
269af69d88dSmrgunlink_block(ralloc_header *info)
270af69d88dSmrg{
271af69d88dSmrg   /* Unlink from parent & siblings */
272af69d88dSmrg   if (info->parent != NULL) {
273af69d88dSmrg      if (info->parent->child == info)
274af69d88dSmrg	 info->parent->child = info->next;
275af69d88dSmrg
276af69d88dSmrg      if (info->prev != NULL)
277af69d88dSmrg	 info->prev->next = info->next;
278af69d88dSmrg
279af69d88dSmrg      if (info->next != NULL)
280af69d88dSmrg	 info->next->prev = info->prev;
281af69d88dSmrg   }
282af69d88dSmrg   info->parent = NULL;
283af69d88dSmrg   info->prev = NULL;
284af69d88dSmrg   info->next = NULL;
285af69d88dSmrg}
286af69d88dSmrg
287af69d88dSmrgstatic void
288af69d88dSmrgunsafe_free(ralloc_header *info)
289af69d88dSmrg{
290af69d88dSmrg   /* Recursively free any children...don't waste time unlinking them. */
291af69d88dSmrg   ralloc_header *temp;
292af69d88dSmrg   while (info->child != NULL) {
293af69d88dSmrg      temp = info->child;
294af69d88dSmrg      info->child = temp->next;
295af69d88dSmrg      unsafe_free(temp);
296af69d88dSmrg   }
297af69d88dSmrg
298af69d88dSmrg   /* Free the block itself.  Call the destructor first, if any. */
299af69d88dSmrg   if (info->destructor != NULL)
300af69d88dSmrg      info->destructor(PTR_FROM_HEADER(info));
301af69d88dSmrg
302af69d88dSmrg   free(info);
303af69d88dSmrg}
304af69d88dSmrg
305af69d88dSmrgvoid
306af69d88dSmrgralloc_steal(const void *new_ctx, void *ptr)
307af69d88dSmrg{
308af69d88dSmrg   ralloc_header *info, *parent;
309af69d88dSmrg
310af69d88dSmrg   if (unlikely(ptr == NULL))
311af69d88dSmrg      return;
312af69d88dSmrg
313af69d88dSmrg   info = get_header(ptr);
3147e995a2eSmrg   parent = new_ctx ? get_header(new_ctx) : NULL;
315af69d88dSmrg
316af69d88dSmrg   unlink_block(info);
317af69d88dSmrg
318af69d88dSmrg   add_child(parent, info);
319af69d88dSmrg}
320af69d88dSmrg
3217e995a2eSmrgvoid
3227e995a2eSmrgralloc_adopt(const void *new_ctx, void *old_ctx)
3237e995a2eSmrg{
3247e995a2eSmrg   ralloc_header *new_info, *old_info, *child;
3257e995a2eSmrg
3267e995a2eSmrg   if (unlikely(old_ctx == NULL))
3277e995a2eSmrg      return;
3287e995a2eSmrg
3297e995a2eSmrg   old_info = get_header(old_ctx);
3307e995a2eSmrg   new_info = get_header(new_ctx);
3317e995a2eSmrg
3327e995a2eSmrg   /* If there are no children, bail. */
3337e995a2eSmrg   if (unlikely(old_info->child == NULL))
3347e995a2eSmrg      return;
3357e995a2eSmrg
3367e995a2eSmrg   /* Set all the children's parent to new_ctx; get a pointer to the last child. */
3377e995a2eSmrg   for (child = old_info->child; child->next != NULL; child = child->next) {
3387e995a2eSmrg      child->parent = new_info;
3397e995a2eSmrg   }
3407e995a2eSmrg   child->parent = new_info;
3417e995a2eSmrg
3427e995a2eSmrg   /* Connect the two lists together; parent them to new_ctx; make old_ctx empty. */
3437e995a2eSmrg   child->next = new_info->child;
3447e995a2eSmrg   if (child->next)
3457e995a2eSmrg      child->next->prev = child;
3467e995a2eSmrg   new_info->child = old_info->child;
3477e995a2eSmrg   old_info->child = NULL;
3487e995a2eSmrg}
3497e995a2eSmrg
350af69d88dSmrgvoid *
351af69d88dSmrgralloc_parent(const void *ptr)
352af69d88dSmrg{
353af69d88dSmrg   ralloc_header *info;
354af69d88dSmrg
355af69d88dSmrg   if (unlikely(ptr == NULL))
356af69d88dSmrg      return NULL;
357af69d88dSmrg
358af69d88dSmrg   info = get_header(ptr);
359af69d88dSmrg   return info->parent ? PTR_FROM_HEADER(info->parent) : NULL;
360af69d88dSmrg}
361af69d88dSmrg
362af69d88dSmrgvoid
363af69d88dSmrgralloc_set_destructor(const void *ptr, void(*destructor)(void *))
364af69d88dSmrg{
365af69d88dSmrg   ralloc_header *info = get_header(ptr);
366af69d88dSmrg   info->destructor = destructor;
367af69d88dSmrg}
368af69d88dSmrg
369af69d88dSmrgchar *
370af69d88dSmrgralloc_strdup(const void *ctx, const char *str)
371af69d88dSmrg{
372af69d88dSmrg   size_t n;
373af69d88dSmrg   char *ptr;
374af69d88dSmrg
375af69d88dSmrg   if (unlikely(str == NULL))
376af69d88dSmrg      return NULL;
377af69d88dSmrg
378af69d88dSmrg   n = strlen(str);
379af69d88dSmrg   ptr = ralloc_array(ctx, char, n + 1);
380af69d88dSmrg   memcpy(ptr, str, n);
381af69d88dSmrg   ptr[n] = '\0';
382af69d88dSmrg   return ptr;
383af69d88dSmrg}
384af69d88dSmrg
385af69d88dSmrgchar *
386af69d88dSmrgralloc_strndup(const void *ctx, const char *str, size_t max)
387af69d88dSmrg{
388af69d88dSmrg   size_t n;
389af69d88dSmrg   char *ptr;
390af69d88dSmrg
391af69d88dSmrg   if (unlikely(str == NULL))
392af69d88dSmrg      return NULL;
393af69d88dSmrg
3947e995a2eSmrg   n = strnlen(str, max);
395af69d88dSmrg   ptr = ralloc_array(ctx, char, n + 1);
396af69d88dSmrg   memcpy(ptr, str, n);
397af69d88dSmrg   ptr[n] = '\0';
398af69d88dSmrg   return ptr;
399af69d88dSmrg}
400af69d88dSmrg
401af69d88dSmrg/* helper routine for strcat/strncat - n is the exact amount to copy */
402af69d88dSmrgstatic bool
403af69d88dSmrgcat(char **dest, const char *str, size_t n)
404af69d88dSmrg{
405af69d88dSmrg   char *both;
406af69d88dSmrg   size_t existing_length;
407af69d88dSmrg   assert(dest != NULL && *dest != NULL);
408af69d88dSmrg
409af69d88dSmrg   existing_length = strlen(*dest);
410af69d88dSmrg   both = resize(*dest, existing_length + n + 1);
411af69d88dSmrg   if (unlikely(both == NULL))
412af69d88dSmrg      return false;
413af69d88dSmrg
414af69d88dSmrg   memcpy(both + existing_length, str, n);
415af69d88dSmrg   both[existing_length + n] = '\0';
416af69d88dSmrg
417af69d88dSmrg   *dest = both;
418af69d88dSmrg   return true;
419af69d88dSmrg}
420af69d88dSmrg
421af69d88dSmrg
422af69d88dSmrgbool
423af69d88dSmrgralloc_strcat(char **dest, const char *str)
424af69d88dSmrg{
425af69d88dSmrg   return cat(dest, str, strlen(str));
426af69d88dSmrg}
427af69d88dSmrg
428af69d88dSmrgbool
429af69d88dSmrgralloc_strncat(char **dest, const char *str, size_t n)
430af69d88dSmrg{
4317e995a2eSmrg   return cat(dest, str, strnlen(str, n));
4327e995a2eSmrg}
4337e995a2eSmrg
4347e995a2eSmrgbool
4357e995a2eSmrgralloc_str_append(char **dest, const char *str,
4367e995a2eSmrg                  size_t existing_length, size_t str_size)
4377e995a2eSmrg{
4387e995a2eSmrg   char *both;
4397e995a2eSmrg   assert(dest != NULL && *dest != NULL);
4407e995a2eSmrg
4417e995a2eSmrg   both = resize(*dest, existing_length + str_size + 1);
4427e995a2eSmrg   if (unlikely(both == NULL))
4437e995a2eSmrg      return false;
444af69d88dSmrg
4457e995a2eSmrg   memcpy(both + existing_length, str, str_size);
4467e995a2eSmrg   both[existing_length + str_size] = '\0';
4477e995a2eSmrg
4487e995a2eSmrg   *dest = both;
4497e995a2eSmrg
4507e995a2eSmrg   return true;
451af69d88dSmrg}
452af69d88dSmrg
453af69d88dSmrgchar *
454af69d88dSmrgralloc_asprintf(const void *ctx, const char *fmt, ...)
455af69d88dSmrg{
456af69d88dSmrg   char *ptr;
457af69d88dSmrg   va_list args;
458af69d88dSmrg   va_start(args, fmt);
459af69d88dSmrg   ptr = ralloc_vasprintf(ctx, fmt, args);
460af69d88dSmrg   va_end(args);
461af69d88dSmrg   return ptr;
462af69d88dSmrg}
463af69d88dSmrg
464af69d88dSmrgchar *
465af69d88dSmrgralloc_vasprintf(const void *ctx, const char *fmt, va_list args)
466af69d88dSmrg{
4671463c08dSmrg   size_t size = u_printf_length(fmt, args) + 1;
468af69d88dSmrg
469af69d88dSmrg   char *ptr = ralloc_size(ctx, size);
470af69d88dSmrg   if (ptr != NULL)
471af69d88dSmrg      vsnprintf(ptr, size, fmt, args);
472af69d88dSmrg
473af69d88dSmrg   return ptr;
474af69d88dSmrg}
475af69d88dSmrg
476af69d88dSmrgbool
477af69d88dSmrgralloc_asprintf_append(char **str, const char *fmt, ...)
478af69d88dSmrg{
479af69d88dSmrg   bool success;
480af69d88dSmrg   va_list args;
481af69d88dSmrg   va_start(args, fmt);
482af69d88dSmrg   success = ralloc_vasprintf_append(str, fmt, args);
483af69d88dSmrg   va_end(args);
484af69d88dSmrg   return success;
485af69d88dSmrg}
486af69d88dSmrg
487af69d88dSmrgbool
488af69d88dSmrgralloc_vasprintf_append(char **str, const char *fmt, va_list args)
489af69d88dSmrg{
490af69d88dSmrg   size_t existing_length;
491af69d88dSmrg   assert(str != NULL);
492af69d88dSmrg   existing_length = *str ? strlen(*str) : 0;
493af69d88dSmrg   return ralloc_vasprintf_rewrite_tail(str, &existing_length, fmt, args);
494af69d88dSmrg}
495af69d88dSmrg
496af69d88dSmrgbool
497af69d88dSmrgralloc_asprintf_rewrite_tail(char **str, size_t *start, const char *fmt, ...)
498af69d88dSmrg{
499af69d88dSmrg   bool success;
500af69d88dSmrg   va_list args;
501af69d88dSmrg   va_start(args, fmt);
502af69d88dSmrg   success = ralloc_vasprintf_rewrite_tail(str, start, fmt, args);
503af69d88dSmrg   va_end(args);
504af69d88dSmrg   return success;
505af69d88dSmrg}
506af69d88dSmrg
507af69d88dSmrgbool
508af69d88dSmrgralloc_vasprintf_rewrite_tail(char **str, size_t *start, const char *fmt,
509af69d88dSmrg			      va_list args)
510af69d88dSmrg{
511af69d88dSmrg   size_t new_length;
512af69d88dSmrg   char *ptr;
513af69d88dSmrg
514af69d88dSmrg   assert(str != NULL);
515af69d88dSmrg
516af69d88dSmrg   if (unlikely(*str == NULL)) {
517af69d88dSmrg      // Assuming a NULL context is probably bad, but it's expected behavior.
518af69d88dSmrg      *str = ralloc_vasprintf(NULL, fmt, args);
5197e995a2eSmrg      *start = strlen(*str);
520af69d88dSmrg      return true;
521af69d88dSmrg   }
522af69d88dSmrg
5231463c08dSmrg   new_length = u_printf_length(fmt, args);
524af69d88dSmrg
525af69d88dSmrg   ptr = resize(*str, *start + new_length + 1);
526af69d88dSmrg   if (unlikely(ptr == NULL))
527af69d88dSmrg      return false;
528af69d88dSmrg
529af69d88dSmrg   vsnprintf(ptr + *start, new_length + 1, fmt, args);
530af69d88dSmrg   *str = ptr;
531af69d88dSmrg   *start += new_length;
532af69d88dSmrg   return true;
533af69d88dSmrg}
5347e995a2eSmrg
5357e995a2eSmrg/***************************************************************************
5367e995a2eSmrg * Linear allocator for short-lived allocations.
5377e995a2eSmrg ***************************************************************************
5387e995a2eSmrg *
5397e995a2eSmrg * The allocator consists of a parent node (2K buffer), which requires
5407e995a2eSmrg * a ralloc parent, and child nodes (allocations). Child nodes can't be freed
5417e995a2eSmrg * directly, because the parent doesn't track them. You have to release
5427e995a2eSmrg * the parent node in order to release all its children.
5437e995a2eSmrg *
5447e995a2eSmrg * The allocator uses a fixed-sized buffer with a monotonically increasing
5457e995a2eSmrg * offset after each allocation. If the buffer is all used, another buffer
5467e995a2eSmrg * is allocated, sharing the same ralloc parent, so all buffers are at
5477e995a2eSmrg * the same level in the ralloc hierarchy.
5487e995a2eSmrg *
5497e995a2eSmrg * The linear parent node is always the first buffer and keeps track of all
5507e995a2eSmrg * other buffers.
5517e995a2eSmrg */
5527e995a2eSmrg
5537e995a2eSmrg#define MIN_LINEAR_BUFSIZE 2048
5547e995a2eSmrg#define SUBALLOC_ALIGNMENT 8
5557e995a2eSmrg#define LMAGIC 0x87b9c7d3
5567e995a2eSmrg
5577e995a2eSmrgstruct
5587e995a2eSmrg#ifdef _MSC_VER
5597e995a2eSmrg __declspec(align(8))
5607e995a2eSmrg#elif defined(__LP64__)
5617e995a2eSmrg __attribute__((aligned(16)))
5627e995a2eSmrg#else
5637e995a2eSmrg __attribute__((aligned(8)))
5647e995a2eSmrg#endif
5657e995a2eSmrg   linear_header {
566d8407755Smaya#ifndef NDEBUG
5677e995a2eSmrg   unsigned magic;   /* for debugging */
5687e995a2eSmrg#endif
5697e995a2eSmrg   unsigned offset;  /* points to the first unused byte in the buffer */
5707e995a2eSmrg   unsigned size;    /* size of the buffer */
5717e995a2eSmrg   void *ralloc_parent;          /* new buffers will use this */
5727e995a2eSmrg   struct linear_header *next;   /* next buffer if we have more */
5737e995a2eSmrg   struct linear_header *latest; /* the only buffer that has free space */
5747e995a2eSmrg
5757e995a2eSmrg   /* After this structure, the buffer begins.
5767e995a2eSmrg    * Each suballocation consists of linear_size_chunk as its header followed
5777e995a2eSmrg    * by the suballocation, so it goes:
5787e995a2eSmrg    *
5797e995a2eSmrg    * - linear_size_chunk
5807e995a2eSmrg    * - allocated space
5817e995a2eSmrg    * - linear_size_chunk
5827e995a2eSmrg    * - allocated space
5837e995a2eSmrg    * etc.
5847e995a2eSmrg    *
5857e995a2eSmrg    * linear_size_chunk is only needed by linear_realloc.
5867e995a2eSmrg    */
5877e995a2eSmrg};
5887e995a2eSmrg
5897e995a2eSmrgstruct linear_size_chunk {
5907e995a2eSmrg   unsigned size; /* for realloc */
5917e995a2eSmrg   unsigned _padding;
5927e995a2eSmrg};
5937e995a2eSmrg
5947e995a2eSmrgtypedef struct linear_header linear_header;
5957e995a2eSmrgtypedef struct linear_size_chunk linear_size_chunk;
5967e995a2eSmrg
5977e995a2eSmrg#define LINEAR_PARENT_TO_HEADER(parent) \
5987e995a2eSmrg   (linear_header*) \
5997e995a2eSmrg   ((char*)(parent) - sizeof(linear_size_chunk) - sizeof(linear_header))
6007e995a2eSmrg
6017e995a2eSmrg/* Allocate the linear buffer with its header. */
6027e995a2eSmrgstatic linear_header *
6037e995a2eSmrgcreate_linear_node(void *ralloc_ctx, unsigned min_size)
6047e995a2eSmrg{
6057e995a2eSmrg   linear_header *node;
6067e995a2eSmrg
6077e995a2eSmrg   min_size += sizeof(linear_size_chunk);
6087e995a2eSmrg
6097e995a2eSmrg   if (likely(min_size < MIN_LINEAR_BUFSIZE))
6107e995a2eSmrg      min_size = MIN_LINEAR_BUFSIZE;
6117e995a2eSmrg
6127e995a2eSmrg   node = ralloc_size(ralloc_ctx, sizeof(linear_header) + min_size);
6137e995a2eSmrg   if (unlikely(!node))
6147e995a2eSmrg      return NULL;
6157e995a2eSmrg
616d8407755Smaya#ifndef NDEBUG
6177e995a2eSmrg   node->magic = LMAGIC;
6187e995a2eSmrg#endif
6197e995a2eSmrg   node->offset = 0;
6207e995a2eSmrg   node->size = min_size;
6217e995a2eSmrg   node->ralloc_parent = ralloc_ctx;
6227e995a2eSmrg   node->next = NULL;
6237e995a2eSmrg   node->latest = node;
6247e995a2eSmrg   return node;
6257e995a2eSmrg}
6267e995a2eSmrg
6277e995a2eSmrgvoid *
6287e995a2eSmrglinear_alloc_child(void *parent, unsigned size)
6297e995a2eSmrg{
6307e995a2eSmrg   linear_header *first = LINEAR_PARENT_TO_HEADER(parent);
6317e995a2eSmrg   linear_header *latest = first->latest;
6327e995a2eSmrg   linear_header *new_node;
6337e995a2eSmrg   linear_size_chunk *ptr;
6347e995a2eSmrg   unsigned full_size;
6357e995a2eSmrg
6367e995a2eSmrg   assert(first->magic == LMAGIC);
6377e995a2eSmrg   assert(!latest->next);
6387e995a2eSmrg
6397e995a2eSmrg   size = ALIGN_POT(size, SUBALLOC_ALIGNMENT);
6407e995a2eSmrg   full_size = sizeof(linear_size_chunk) + size;
6417e995a2eSmrg
6427e995a2eSmrg   if (unlikely(latest->offset + full_size > latest->size)) {
6437e995a2eSmrg      /* allocate a new node */
6447e995a2eSmrg      new_node = create_linear_node(latest->ralloc_parent, size);
6457e995a2eSmrg      if (unlikely(!new_node))
6467e995a2eSmrg         return NULL;
6477e995a2eSmrg
6487e995a2eSmrg      first->latest = new_node;
6497e995a2eSmrg      latest->latest = new_node;
6507e995a2eSmrg      latest->next = new_node;
6517e995a2eSmrg      latest = new_node;
6527e995a2eSmrg   }
6537e995a2eSmrg
6547e995a2eSmrg   ptr = (linear_size_chunk *)((char*)&latest[1] + latest->offset);
6557e995a2eSmrg   ptr->size = size;
6567e995a2eSmrg   latest->offset += full_size;
6577e995a2eSmrg
6587e995a2eSmrg   assert((uintptr_t)&ptr[1] % SUBALLOC_ALIGNMENT == 0);
6597e995a2eSmrg   return &ptr[1];
6607e995a2eSmrg}
6617e995a2eSmrg
6627e995a2eSmrgvoid *
6637e995a2eSmrglinear_alloc_parent(void *ralloc_ctx, unsigned size)
6647e995a2eSmrg{
6657e995a2eSmrg   linear_header *node;
6667e995a2eSmrg
6677e995a2eSmrg   if (unlikely(!ralloc_ctx))
6687e995a2eSmrg      return NULL;
6697e995a2eSmrg
6707e995a2eSmrg   size = ALIGN_POT(size, SUBALLOC_ALIGNMENT);
6717e995a2eSmrg
6727e995a2eSmrg   node = create_linear_node(ralloc_ctx, size);
6737e995a2eSmrg   if (unlikely(!node))
6747e995a2eSmrg      return NULL;
6757e995a2eSmrg
6767e995a2eSmrg   return linear_alloc_child((char*)node +
6777e995a2eSmrg                             sizeof(linear_header) +
6787e995a2eSmrg                             sizeof(linear_size_chunk), size);
6797e995a2eSmrg}
6807e995a2eSmrg
6817e995a2eSmrgvoid *
6827e995a2eSmrglinear_zalloc_child(void *parent, unsigned size)
6837e995a2eSmrg{
6847e995a2eSmrg   void *ptr = linear_alloc_child(parent, size);
6857e995a2eSmrg
6867e995a2eSmrg   if (likely(ptr))
6877e995a2eSmrg      memset(ptr, 0, size);
6887e995a2eSmrg   return ptr;
6897e995a2eSmrg}
6907e995a2eSmrg
6917e995a2eSmrgvoid *
6927e995a2eSmrglinear_zalloc_parent(void *parent, unsigned size)
6937e995a2eSmrg{
6947e995a2eSmrg   void *ptr = linear_alloc_parent(parent, size);
6957e995a2eSmrg
6967e995a2eSmrg   if (likely(ptr))
6977e995a2eSmrg      memset(ptr, 0, size);
6987e995a2eSmrg   return ptr;
6997e995a2eSmrg}
7007e995a2eSmrg
7017e995a2eSmrgvoid
7027e995a2eSmrglinear_free_parent(void *ptr)
7037e995a2eSmrg{
7047e995a2eSmrg   linear_header *node;
7057e995a2eSmrg
7067e995a2eSmrg   if (unlikely(!ptr))
7077e995a2eSmrg      return;
7087e995a2eSmrg
7097e995a2eSmrg   node = LINEAR_PARENT_TO_HEADER(ptr);
7107e995a2eSmrg   assert(node->magic == LMAGIC);
7117e995a2eSmrg
7127e995a2eSmrg   while (node) {
7137e995a2eSmrg      void *ptr = node;
7147e995a2eSmrg
7157e995a2eSmrg      node = node->next;
7167e995a2eSmrg      ralloc_free(ptr);
7177e995a2eSmrg   }
7187e995a2eSmrg}
7197e995a2eSmrg
7207e995a2eSmrgvoid
7217e995a2eSmrgralloc_steal_linear_parent(void *new_ralloc_ctx, void *ptr)
7227e995a2eSmrg{
7237e995a2eSmrg   linear_header *node;
7247e995a2eSmrg
7257e995a2eSmrg   if (unlikely(!ptr))
7267e995a2eSmrg      return;
7277e995a2eSmrg
7287e995a2eSmrg   node = LINEAR_PARENT_TO_HEADER(ptr);
7297e995a2eSmrg   assert(node->magic == LMAGIC);
7307e995a2eSmrg
7317e995a2eSmrg   while (node) {
7327e995a2eSmrg      ralloc_steal(new_ralloc_ctx, node);
7337e995a2eSmrg      node->ralloc_parent = new_ralloc_ctx;
7347e995a2eSmrg      node = node->next;
7357e995a2eSmrg   }
7367e995a2eSmrg}
7377e995a2eSmrg
7387e995a2eSmrgvoid *
7397e995a2eSmrgralloc_parent_of_linear_parent(void *ptr)
7407e995a2eSmrg{
7417e995a2eSmrg   linear_header *node = LINEAR_PARENT_TO_HEADER(ptr);
7427e995a2eSmrg   assert(node->magic == LMAGIC);
7437e995a2eSmrg   return node->ralloc_parent;
7447e995a2eSmrg}
7457e995a2eSmrg
7467e995a2eSmrgvoid *
7477e995a2eSmrglinear_realloc(void *parent, void *old, unsigned new_size)
7487e995a2eSmrg{
7497e995a2eSmrg   unsigned old_size = 0;
7507e995a2eSmrg   ralloc_header *new_ptr;
7517e995a2eSmrg
7527e995a2eSmrg   new_ptr = linear_alloc_child(parent, new_size);
7537e995a2eSmrg
7547e995a2eSmrg   if (unlikely(!old))
7557e995a2eSmrg      return new_ptr;
7567e995a2eSmrg
7577e995a2eSmrg   old_size = ((linear_size_chunk*)old)[-1].size;
7587e995a2eSmrg
7597e995a2eSmrg   if (likely(new_ptr && old_size))
7607e995a2eSmrg      memcpy(new_ptr, old, MIN2(old_size, new_size));
7617e995a2eSmrg
7627e995a2eSmrg   return new_ptr;
7637e995a2eSmrg}
7647e995a2eSmrg
7657e995a2eSmrg/* All code below is pretty much copied from ralloc and only the alloc
7667e995a2eSmrg * calls are different.
7677e995a2eSmrg */
7687e995a2eSmrg
7697e995a2eSmrgchar *
7707e995a2eSmrglinear_strdup(void *parent, const char *str)
7717e995a2eSmrg{
7727e995a2eSmrg   unsigned n;
7737e995a2eSmrg   char *ptr;
7747e995a2eSmrg
7757e995a2eSmrg   if (unlikely(!str))
7767e995a2eSmrg      return NULL;
7777e995a2eSmrg
7787e995a2eSmrg   n = strlen(str);
7797e995a2eSmrg   ptr = linear_alloc_child(parent, n + 1);
7807e995a2eSmrg   if (unlikely(!ptr))
7817e995a2eSmrg      return NULL;
7827e995a2eSmrg
7837e995a2eSmrg   memcpy(ptr, str, n);
7847e995a2eSmrg   ptr[n] = '\0';
7857e995a2eSmrg   return ptr;
7867e995a2eSmrg}
7877e995a2eSmrg
7887e995a2eSmrgchar *
7897e995a2eSmrglinear_asprintf(void *parent, const char *fmt, ...)
7907e995a2eSmrg{
7917e995a2eSmrg   char *ptr;
7927e995a2eSmrg   va_list args;
7937e995a2eSmrg   va_start(args, fmt);
7947e995a2eSmrg   ptr = linear_vasprintf(parent, fmt, args);
7957e995a2eSmrg   va_end(args);
7967e995a2eSmrg   return ptr;
7977e995a2eSmrg}
7987e995a2eSmrg
7997e995a2eSmrgchar *
8007e995a2eSmrglinear_vasprintf(void *parent, const char *fmt, va_list args)
8017e995a2eSmrg{
8021463c08dSmrg   unsigned size = u_printf_length(fmt, args) + 1;
8037e995a2eSmrg
8047e995a2eSmrg   char *ptr = linear_alloc_child(parent, size);
8057e995a2eSmrg   if (ptr != NULL)
8067e995a2eSmrg      vsnprintf(ptr, size, fmt, args);
8077e995a2eSmrg
8087e995a2eSmrg   return ptr;
8097e995a2eSmrg}
8107e995a2eSmrg
8117e995a2eSmrgbool
8127e995a2eSmrglinear_asprintf_append(void *parent, char **str, const char *fmt, ...)
8137e995a2eSmrg{
8147e995a2eSmrg   bool success;
8157e995a2eSmrg   va_list args;
8167e995a2eSmrg   va_start(args, fmt);
8177e995a2eSmrg   success = linear_vasprintf_append(parent, str, fmt, args);
8187e995a2eSmrg   va_end(args);
8197e995a2eSmrg   return success;
8207e995a2eSmrg}
8217e995a2eSmrg
8227e995a2eSmrgbool
8237e995a2eSmrglinear_vasprintf_append(void *parent, char **str, const char *fmt, va_list args)
8247e995a2eSmrg{
8257e995a2eSmrg   size_t existing_length;
8267e995a2eSmrg   assert(str != NULL);
8277e995a2eSmrg   existing_length = *str ? strlen(*str) : 0;
8287e995a2eSmrg   return linear_vasprintf_rewrite_tail(parent, str, &existing_length, fmt, args);
8297e995a2eSmrg}
8307e995a2eSmrg
8317e995a2eSmrgbool
8327e995a2eSmrglinear_asprintf_rewrite_tail(void *parent, char **str, size_t *start,
8337e995a2eSmrg                             const char *fmt, ...)
8347e995a2eSmrg{
8357e995a2eSmrg   bool success;
8367e995a2eSmrg   va_list args;
8377e995a2eSmrg   va_start(args, fmt);
8387e995a2eSmrg   success = linear_vasprintf_rewrite_tail(parent, str, start, fmt, args);
8397e995a2eSmrg   va_end(args);
8407e995a2eSmrg   return success;
8417e995a2eSmrg}
8427e995a2eSmrg
8437e995a2eSmrgbool
8447e995a2eSmrglinear_vasprintf_rewrite_tail(void *parent, char **str, size_t *start,
8457e995a2eSmrg                              const char *fmt, va_list args)
8467e995a2eSmrg{
8477e995a2eSmrg   size_t new_length;
8487e995a2eSmrg   char *ptr;
8497e995a2eSmrg
8507e995a2eSmrg   assert(str != NULL);
8517e995a2eSmrg
8527e995a2eSmrg   if (unlikely(*str == NULL)) {
8537e995a2eSmrg      *str = linear_vasprintf(parent, fmt, args);
8547e995a2eSmrg      *start = strlen(*str);
8557e995a2eSmrg      return true;
8567e995a2eSmrg   }
8577e995a2eSmrg
8581463c08dSmrg   new_length = u_printf_length(fmt, args);
8597e995a2eSmrg
8607e995a2eSmrg   ptr = linear_realloc(parent, *str, *start + new_length + 1);
8617e995a2eSmrg   if (unlikely(ptr == NULL))
8627e995a2eSmrg      return false;
8637e995a2eSmrg
8647e995a2eSmrg   vsnprintf(ptr + *start, new_length + 1, fmt, args);
8657e995a2eSmrg   *str = ptr;
8667e995a2eSmrg   *start += new_length;
8677e995a2eSmrg   return true;
8687e995a2eSmrg}
8697e995a2eSmrg
8707e995a2eSmrg/* helper routine for strcat/strncat - n is the exact amount to copy */
8717e995a2eSmrgstatic bool
8727e995a2eSmrglinear_cat(void *parent, char **dest, const char *str, unsigned n)
8737e995a2eSmrg{
8747e995a2eSmrg   char *both;
8757e995a2eSmrg   unsigned existing_length;
8767e995a2eSmrg   assert(dest != NULL && *dest != NULL);
8777e995a2eSmrg
8787e995a2eSmrg   existing_length = strlen(*dest);
8797e995a2eSmrg   both = linear_realloc(parent, *dest, existing_length + n + 1);
8807e995a2eSmrg   if (unlikely(both == NULL))
8817e995a2eSmrg      return false;
8827e995a2eSmrg
8837e995a2eSmrg   memcpy(both + existing_length, str, n);
8847e995a2eSmrg   both[existing_length + n] = '\0';
8857e995a2eSmrg
8867e995a2eSmrg   *dest = both;
8877e995a2eSmrg   return true;
8887e995a2eSmrg}
8897e995a2eSmrg
8907e995a2eSmrgbool
8917e995a2eSmrglinear_strcat(void *parent, char **dest, const char *str)
8927e995a2eSmrg{
8937e995a2eSmrg   return linear_cat(parent, dest, str, strlen(str));
8947e995a2eSmrg}
895