• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2010 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdint.h>
30 
31 #include "util/macros.h"
32 #include "util/u_math.h"
33 
34 /* Some versions of MinGW are missing _vscprintf's declaration, although they
35  * still provide the symbol in the import library. */
36 #ifdef __MINGW32__
37 _CRTIMP int _vscprintf(const char *format, va_list argptr);
38 #endif
39 
40 #include "ralloc.h"
41 
42 #ifndef va_copy
43 #ifdef __va_copy
44 #define va_copy(dest, src) __va_copy((dest), (src))
45 #else
46 #define va_copy(dest, src) (dest) = (src)
47 #endif
48 #endif
49 
50 #define CANARY 0x5A1106
51 
52 /* Align the header's size so that ralloc() allocations will return with the
53  * same alignment as a libc malloc would have (8 on 32-bit GLIBC, 16 on
54  * 64-bit), avoiding performance penalities on x86 and alignment faults on
55  * ARM.
56  */
57 struct
58 #ifdef _MSC_VER
59 #if _WIN64
60 __declspec(align(16))
61 #else
62  __declspec(align(8))
63 #endif
64 #elif defined(__LP64__)
65  __attribute__((aligned(16)))
66 #else
67  __attribute__((aligned(8)))
68 #endif
69    ralloc_header
70 {
71 #ifndef NDEBUG
72    /* A canary value used to determine whether a pointer is ralloc'd. */
73    unsigned canary;
74 #endif
75 
76    struct ralloc_header *parent;
77 
78    /* The first child (head of a linked list) */
79    struct ralloc_header *child;
80 
81    /* Linked list of siblings */
82    struct ralloc_header *prev;
83    struct ralloc_header *next;
84 
85    void (*destructor)(void *);
86 };
87 
88 typedef struct ralloc_header ralloc_header;
89 
90 static void unlink_block(ralloc_header *info);
91 static void unsafe_free(ralloc_header *info);
92 
93 static ralloc_header *
get_header(const void * ptr)94 get_header(const void *ptr)
95 {
96    ralloc_header *info = (ralloc_header *) (((char *) ptr) -
97 					    sizeof(ralloc_header));
98    assert(info->canary == CANARY);
99    return info;
100 }
101 
102 #define PTR_FROM_HEADER(info) (((char *) info) + sizeof(ralloc_header))
103 
104 static void
add_child(ralloc_header * parent,ralloc_header * info)105 add_child(ralloc_header *parent, ralloc_header *info)
106 {
107    if (parent != NULL) {
108       info->parent = parent;
109       info->next = parent->child;
110       parent->child = info;
111 
112       if (info->next != NULL)
113 	 info->next->prev = info;
114    }
115 }
116 
117 void *
ralloc_context(const void * ctx)118 ralloc_context(const void *ctx)
119 {
120    return ralloc_size(ctx, 0);
121 }
122 
123 void *
ralloc_size(const void * ctx,size_t size)124 ralloc_size(const void *ctx, size_t size)
125 {
126    /* Some malloc allocation doesn't always align to 16 bytes even on 64 bits
127     * system, from Android bionic/tests/malloc_test.cpp:
128     *  - Allocations of a size that rounds up to a multiple of 16 bytes
129     *    must have at least 16 byte alignment.
130     *  - Allocations of a size that rounds up to a multiple of 8 bytes and
131     *    not 16 bytes, are only required to have at least 8 byte alignment.
132     */
133    void *block = malloc(align64(size + sizeof(ralloc_header),
134                                 alignof(ralloc_header)));
135    ralloc_header *info;
136    ralloc_header *parent;
137 
138    if (unlikely(block == NULL))
139       return NULL;
140 
141    info = (ralloc_header *) block;
142    /* measurements have shown that calloc is slower (because of
143     * the multiplication overflow checking?), so clear things
144     * manually
145     */
146    info->parent = NULL;
147    info->child = NULL;
148    info->prev = NULL;
149    info->next = NULL;
150    info->destructor = NULL;
151 
152    parent = ctx != NULL ? get_header(ctx) : NULL;
153 
154    add_child(parent, info);
155 
156 #ifndef NDEBUG
157    info->canary = CANARY;
158 #endif
159 
160    return PTR_FROM_HEADER(info);
161 }
162 
163 void *
rzalloc_size(const void * ctx,size_t size)164 rzalloc_size(const void *ctx, size_t size)
165 {
166    void *ptr = ralloc_size(ctx, size);
167 
168    if (likely(ptr))
169       memset(ptr, 0, size);
170 
171    return ptr;
172 }
173 
174 /* helper function - assumes ptr != NULL */
175 static void *
resize(void * ptr,size_t size)176 resize(void *ptr, size_t size)
177 {
178    ralloc_header *child, *old, *info;
179 
180    old = get_header(ptr);
181    info = realloc(old, align64(size + sizeof(ralloc_header),
182                                alignof(ralloc_header)));
183 
184    if (info == NULL)
185       return NULL;
186 
187    /* Update parent and sibling's links to the reallocated node. */
188    if (info != old && info->parent != NULL) {
189       if (info->parent->child == old)
190 	 info->parent->child = info;
191 
192       if (info->prev != NULL)
193 	 info->prev->next = info;
194 
195       if (info->next != NULL)
196 	 info->next->prev = info;
197    }
198 
199    /* Update child->parent links for all children */
200    for (child = info->child; child != NULL; child = child->next)
201       child->parent = info;
202 
203    return PTR_FROM_HEADER(info);
204 }
205 
206 void *
reralloc_size(const void * ctx,void * ptr,size_t size)207 reralloc_size(const void *ctx, void *ptr, size_t size)
208 {
209    if (unlikely(ptr == NULL))
210       return ralloc_size(ctx, size);
211 
212    assert(ralloc_parent(ptr) == ctx);
213    return resize(ptr, size);
214 }
215 
216 void *
rerzalloc_size(const void * ctx,void * ptr,size_t old_size,size_t new_size)217 rerzalloc_size(const void *ctx, void *ptr, size_t old_size, size_t new_size)
218 {
219    if (unlikely(ptr == NULL))
220       return rzalloc_size(ctx, new_size);
221 
222    assert(ralloc_parent(ptr) == ctx);
223    ptr = resize(ptr, new_size);
224 
225    if (new_size > old_size)
226       memset((char *)ptr + old_size, 0, new_size - old_size);
227 
228    return ptr;
229 }
230 
231 void *
ralloc_array_size(const void * ctx,size_t size,unsigned count)232 ralloc_array_size(const void *ctx, size_t size, unsigned count)
233 {
234    if (count > SIZE_MAX/size)
235       return NULL;
236 
237    return ralloc_size(ctx, size * count);
238 }
239 
240 void *
rzalloc_array_size(const void * ctx,size_t size,unsigned count)241 rzalloc_array_size(const void *ctx, size_t size, unsigned count)
242 {
243    if (count > SIZE_MAX/size)
244       return NULL;
245 
246    return rzalloc_size(ctx, size * count);
247 }
248 
249 void *
reralloc_array_size(const void * ctx,void * ptr,size_t size,unsigned count)250 reralloc_array_size(const void *ctx, void *ptr, size_t size, unsigned count)
251 {
252    if (count > SIZE_MAX/size)
253       return NULL;
254 
255    return reralloc_size(ctx, ptr, size * count);
256 }
257 
258 void *
rerzalloc_array_size(const void * ctx,void * ptr,size_t size,unsigned old_count,unsigned new_count)259 rerzalloc_array_size(const void *ctx, void *ptr, size_t size,
260                      unsigned old_count, unsigned new_count)
261 {
262    if (new_count > SIZE_MAX/size)
263       return NULL;
264 
265    return rerzalloc_size(ctx, ptr, size * old_count, size * new_count);
266 }
267 
268 void
ralloc_free(void * ptr)269 ralloc_free(void *ptr)
270 {
271    ralloc_header *info;
272 
273    if (ptr == NULL)
274       return;
275 
276    info = get_header(ptr);
277    unlink_block(info);
278    unsafe_free(info);
279 }
280 
281 static void
unlink_block(ralloc_header * info)282 unlink_block(ralloc_header *info)
283 {
284    /* Unlink from parent & siblings */
285    if (info->parent != NULL) {
286       if (info->parent->child == info)
287 	 info->parent->child = info->next;
288 
289       if (info->prev != NULL)
290 	 info->prev->next = info->next;
291 
292       if (info->next != NULL)
293 	 info->next->prev = info->prev;
294    }
295    info->parent = NULL;
296    info->prev = NULL;
297    info->next = NULL;
298 }
299 
300 static void
unsafe_free(ralloc_header * info)301 unsafe_free(ralloc_header *info)
302 {
303    /* Recursively free any children...don't waste time unlinking them. */
304    ralloc_header *temp;
305    while (info->child != NULL) {
306       temp = info->child;
307       info->child = temp->next;
308       unsafe_free(temp);
309    }
310 
311    /* Free the block itself.  Call the destructor first, if any. */
312    if (info->destructor != NULL)
313       info->destructor(PTR_FROM_HEADER(info));
314 
315    free(info);
316 }
317 
318 void
ralloc_steal(const void * new_ctx,void * ptr)319 ralloc_steal(const void *new_ctx, void *ptr)
320 {
321    ralloc_header *info, *parent;
322 
323    if (unlikely(ptr == NULL))
324       return;
325 
326    info = get_header(ptr);
327    parent = new_ctx ? get_header(new_ctx) : NULL;
328 
329    unlink_block(info);
330 
331    add_child(parent, info);
332 }
333 
334 void
ralloc_adopt(const void * new_ctx,void * old_ctx)335 ralloc_adopt(const void *new_ctx, void *old_ctx)
336 {
337    ralloc_header *new_info, *old_info, *child;
338 
339    if (unlikely(old_ctx == NULL))
340       return;
341 
342    old_info = get_header(old_ctx);
343    new_info = get_header(new_ctx);
344 
345    /* If there are no children, bail. */
346    if (unlikely(old_info->child == NULL))
347       return;
348 
349    /* Set all the children's parent to new_ctx; get a pointer to the last child. */
350    for (child = old_info->child; child->next != NULL; child = child->next) {
351       child->parent = new_info;
352    }
353    child->parent = new_info;
354 
355    /* Connect the two lists together; parent them to new_ctx; make old_ctx empty. */
356    child->next = new_info->child;
357    if (child->next)
358       child->next->prev = child;
359    new_info->child = old_info->child;
360    old_info->child = NULL;
361 }
362 
363 void *
ralloc_parent(const void * ptr)364 ralloc_parent(const void *ptr)
365 {
366    ralloc_header *info;
367 
368    if (unlikely(ptr == NULL))
369       return NULL;
370 
371    info = get_header(ptr);
372    return info->parent ? PTR_FROM_HEADER(info->parent) : NULL;
373 }
374 
375 void
ralloc_set_destructor(const void * ptr,void (* destructor)(void *))376 ralloc_set_destructor(const void *ptr, void(*destructor)(void *))
377 {
378    ralloc_header *info = get_header(ptr);
379    info->destructor = destructor;
380 }
381 
382 char *
ralloc_strdup(const void * ctx,const char * str)383 ralloc_strdup(const void *ctx, const char *str)
384 {
385    size_t n;
386    char *ptr;
387 
388    if (unlikely(str == NULL))
389       return NULL;
390 
391    n = strlen(str);
392    ptr = ralloc_array(ctx, char, n + 1);
393    memcpy(ptr, str, n);
394    ptr[n] = '\0';
395    return ptr;
396 }
397 
398 char *
ralloc_strndup(const void * ctx,const char * str,size_t max)399 ralloc_strndup(const void *ctx, const char *str, size_t max)
400 {
401    size_t n;
402    char *ptr;
403 
404    if (unlikely(str == NULL))
405       return NULL;
406 
407    n = strnlen(str, max);
408    ptr = ralloc_array(ctx, char, n + 1);
409    memcpy(ptr, str, n);
410    ptr[n] = '\0';
411    return ptr;
412 }
413 
414 /* helper routine for strcat/strncat - n is the exact amount to copy */
415 static bool
cat(char ** dest,const char * str,size_t n)416 cat(char **dest, const char *str, size_t n)
417 {
418    char *both;
419    size_t existing_length;
420    assert(dest != NULL && *dest != NULL);
421 
422    existing_length = strlen(*dest);
423    both = resize(*dest, existing_length + n + 1);
424    if (unlikely(both == NULL))
425       return false;
426 
427    memcpy(both + existing_length, str, n);
428    both[existing_length + n] = '\0';
429 
430    *dest = both;
431    return true;
432 }
433 
434 
435 bool
ralloc_strcat(char ** dest,const char * str)436 ralloc_strcat(char **dest, const char *str)
437 {
438    return cat(dest, str, strlen(str));
439 }
440 
441 bool
ralloc_strncat(char ** dest,const char * str,size_t n)442 ralloc_strncat(char **dest, const char *str, size_t n)
443 {
444    return cat(dest, str, strnlen(str, n));
445 }
446 
447 bool
ralloc_str_append(char ** dest,const char * str,size_t existing_length,size_t str_size)448 ralloc_str_append(char **dest, const char *str,
449                   size_t existing_length, size_t str_size)
450 {
451    char *both;
452    assert(dest != NULL && *dest != NULL);
453 
454    both = resize(*dest, existing_length + str_size + 1);
455    if (unlikely(both == NULL))
456       return false;
457 
458    memcpy(both + existing_length, str, str_size);
459    both[existing_length + str_size] = '\0';
460 
461    *dest = both;
462 
463    return true;
464 }
465 
466 char *
ralloc_asprintf(const void * ctx,const char * fmt,...)467 ralloc_asprintf(const void *ctx, const char *fmt, ...)
468 {
469    char *ptr;
470    va_list args;
471    va_start(args, fmt);
472    ptr = ralloc_vasprintf(ctx, fmt, args);
473    va_end(args);
474    return ptr;
475 }
476 
477 /* Return the length of the string that would be generated by a printf-style
478  * format and argument list, not including the \0 byte.
479  */
480 static size_t
printf_length(const char * fmt,va_list untouched_args)481 printf_length(const char *fmt, va_list untouched_args)
482 {
483    int size;
484    char junk;
485 
486    /* Make a copy of the va_list so the original caller can still use it */
487    va_list args;
488    va_copy(args, untouched_args);
489 
490 #ifdef _WIN32
491    /* We need to use _vcsprintf to calculate the size as vsnprintf returns -1
492     * if the number of characters to write is greater than count.
493     */
494    size = _vscprintf(fmt, args);
495    (void)junk;
496 #else
497    size = vsnprintf(&junk, 1, fmt, args);
498 #endif
499    assert(size >= 0);
500 
501    va_end(args);
502 
503    return size;
504 }
505 
506 char *
ralloc_vasprintf(const void * ctx,const char * fmt,va_list args)507 ralloc_vasprintf(const void *ctx, const char *fmt, va_list args)
508 {
509    size_t size = printf_length(fmt, args) + 1;
510 
511    char *ptr = ralloc_size(ctx, size);
512    if (ptr != NULL)
513       vsnprintf(ptr, size, fmt, args);
514 
515    return ptr;
516 }
517 
518 bool
ralloc_asprintf_append(char ** str,const char * fmt,...)519 ralloc_asprintf_append(char **str, const char *fmt, ...)
520 {
521    bool success;
522    va_list args;
523    va_start(args, fmt);
524    success = ralloc_vasprintf_append(str, fmt, args);
525    va_end(args);
526    return success;
527 }
528 
529 bool
ralloc_vasprintf_append(char ** str,const char * fmt,va_list args)530 ralloc_vasprintf_append(char **str, const char *fmt, va_list args)
531 {
532    size_t existing_length;
533    assert(str != NULL);
534    existing_length = *str ? strlen(*str) : 0;
535    return ralloc_vasprintf_rewrite_tail(str, &existing_length, fmt, args);
536 }
537 
538 bool
ralloc_asprintf_rewrite_tail(char ** str,size_t * start,const char * fmt,...)539 ralloc_asprintf_rewrite_tail(char **str, size_t *start, const char *fmt, ...)
540 {
541    bool success;
542    va_list args;
543    va_start(args, fmt);
544    success = ralloc_vasprintf_rewrite_tail(str, start, fmt, args);
545    va_end(args);
546    return success;
547 }
548 
549 bool
ralloc_vasprintf_rewrite_tail(char ** str,size_t * start,const char * fmt,va_list args)550 ralloc_vasprintf_rewrite_tail(char **str, size_t *start, const char *fmt,
551 			      va_list args)
552 {
553    size_t new_length;
554    char *ptr;
555 
556    assert(str != NULL);
557 
558    if (unlikely(*str == NULL)) {
559       // Assuming a NULL context is probably bad, but it's expected behavior.
560       *str = ralloc_vasprintf(NULL, fmt, args);
561       *start = strlen(*str);
562       return true;
563    }
564 
565    new_length = printf_length(fmt, args);
566 
567    ptr = resize(*str, *start + new_length + 1);
568    if (unlikely(ptr == NULL))
569       return false;
570 
571    vsnprintf(ptr + *start, new_length + 1, fmt, args);
572    *str = ptr;
573    *start += new_length;
574    return true;
575 }
576 
577 /***************************************************************************
578  * Linear allocator for short-lived allocations.
579  ***************************************************************************
580  *
581  * The allocator consists of a parent node (2K buffer), which requires
582  * a ralloc parent, and child nodes (allocations). Child nodes can't be freed
583  * directly, because the parent doesn't track them. You have to release
584  * the parent node in order to release all its children.
585  *
586  * The allocator uses a fixed-sized buffer with a monotonically increasing
587  * offset after each allocation. If the buffer is all used, another buffer
588  * is allocated, sharing the same ralloc parent, so all buffers are at
589  * the same level in the ralloc hierarchy.
590  *
591  * The linear parent node is always the first buffer and keeps track of all
592  * other buffers.
593  */
594 
595 #define MIN_LINEAR_BUFSIZE 2048
596 #define SUBALLOC_ALIGNMENT 8
597 #define LMAGIC 0x87b9c7d3
598 
599 struct
600 #ifdef _MSC_VER
601  __declspec(align(8))
602 #elif defined(__LP64__)
603  __attribute__((aligned(16)))
604 #else
605  __attribute__((aligned(8)))
606 #endif
607    linear_header {
608 #ifndef NDEBUG
609    unsigned magic;   /* for debugging */
610 #endif
611    unsigned offset;  /* points to the first unused byte in the buffer */
612    unsigned size;    /* size of the buffer */
613    void *ralloc_parent;          /* new buffers will use this */
614    struct linear_header *next;   /* next buffer if we have more */
615    struct linear_header *latest; /* the only buffer that has free space */
616 
617    /* After this structure, the buffer begins.
618     * Each suballocation consists of linear_size_chunk as its header followed
619     * by the suballocation, so it goes:
620     *
621     * - linear_size_chunk
622     * - allocated space
623     * - linear_size_chunk
624     * - allocated space
625     * etc.
626     *
627     * linear_size_chunk is only needed by linear_realloc.
628     */
629 };
630 
631 struct linear_size_chunk {
632    unsigned size; /* for realloc */
633    unsigned _padding;
634 };
635 
636 typedef struct linear_header linear_header;
637 typedef struct linear_size_chunk linear_size_chunk;
638 
639 #define LINEAR_PARENT_TO_HEADER(parent) \
640    (linear_header*) \
641    ((char*)(parent) - sizeof(linear_size_chunk) - sizeof(linear_header))
642 
643 /* Allocate the linear buffer with its header. */
644 static linear_header *
create_linear_node(void * ralloc_ctx,unsigned min_size)645 create_linear_node(void *ralloc_ctx, unsigned min_size)
646 {
647    linear_header *node;
648 
649    min_size += sizeof(linear_size_chunk);
650 
651    if (likely(min_size < MIN_LINEAR_BUFSIZE))
652       min_size = MIN_LINEAR_BUFSIZE;
653 
654    node = ralloc_size(ralloc_ctx, sizeof(linear_header) + min_size);
655    if (unlikely(!node))
656       return NULL;
657 
658 #ifndef NDEBUG
659    node->magic = LMAGIC;
660 #endif
661    node->offset = 0;
662    node->size = min_size;
663    node->ralloc_parent = ralloc_ctx;
664    node->next = NULL;
665    node->latest = node;
666    return node;
667 }
668 
669 void *
linear_alloc_child(void * parent,unsigned size)670 linear_alloc_child(void *parent, unsigned size)
671 {
672    linear_header *first = LINEAR_PARENT_TO_HEADER(parent);
673    linear_header *latest = first->latest;
674    linear_header *new_node;
675    linear_size_chunk *ptr;
676    unsigned full_size;
677 
678    assert(first->magic == LMAGIC);
679    assert(!latest->next);
680 
681    size = ALIGN_POT(size, SUBALLOC_ALIGNMENT);
682    full_size = sizeof(linear_size_chunk) + size;
683 
684    if (unlikely(latest->offset + full_size > latest->size)) {
685       /* allocate a new node */
686       new_node = create_linear_node(latest->ralloc_parent, size);
687       if (unlikely(!new_node))
688          return NULL;
689 
690       first->latest = new_node;
691       latest->latest = new_node;
692       latest->next = new_node;
693       latest = new_node;
694    }
695 
696    ptr = (linear_size_chunk *)((char*)&latest[1] + latest->offset);
697    ptr->size = size;
698    latest->offset += full_size;
699 
700    assert((uintptr_t)&ptr[1] % SUBALLOC_ALIGNMENT == 0);
701    return &ptr[1];
702 }
703 
704 void *
linear_alloc_parent(void * ralloc_ctx,unsigned size)705 linear_alloc_parent(void *ralloc_ctx, unsigned size)
706 {
707    linear_header *node;
708 
709    if (unlikely(!ralloc_ctx))
710       return NULL;
711 
712    size = ALIGN_POT(size, SUBALLOC_ALIGNMENT);
713 
714    node = create_linear_node(ralloc_ctx, size);
715    if (unlikely(!node))
716       return NULL;
717 
718    return linear_alloc_child((char*)node +
719                              sizeof(linear_header) +
720                              sizeof(linear_size_chunk), size);
721 }
722 
723 void *
linear_zalloc_child(void * parent,unsigned size)724 linear_zalloc_child(void *parent, unsigned size)
725 {
726    void *ptr = linear_alloc_child(parent, size);
727 
728    if (likely(ptr))
729       memset(ptr, 0, size);
730    return ptr;
731 }
732 
733 void *
linear_zalloc_parent(void * parent,unsigned size)734 linear_zalloc_parent(void *parent, unsigned size)
735 {
736    void *ptr = linear_alloc_parent(parent, size);
737 
738    if (likely(ptr))
739       memset(ptr, 0, size);
740    return ptr;
741 }
742 
743 void
linear_free_parent(void * ptr)744 linear_free_parent(void *ptr)
745 {
746    linear_header *node;
747 
748    if (unlikely(!ptr))
749       return;
750 
751    node = LINEAR_PARENT_TO_HEADER(ptr);
752    assert(node->magic == LMAGIC);
753 
754    while (node) {
755       void *ptr = node;
756 
757       node = node->next;
758       ralloc_free(ptr);
759    }
760 }
761 
762 void
ralloc_steal_linear_parent(void * new_ralloc_ctx,void * ptr)763 ralloc_steal_linear_parent(void *new_ralloc_ctx, void *ptr)
764 {
765    linear_header *node;
766 
767    if (unlikely(!ptr))
768       return;
769 
770    node = LINEAR_PARENT_TO_HEADER(ptr);
771    assert(node->magic == LMAGIC);
772 
773    while (node) {
774       ralloc_steal(new_ralloc_ctx, node);
775       node->ralloc_parent = new_ralloc_ctx;
776       node = node->next;
777    }
778 }
779 
780 void *
ralloc_parent_of_linear_parent(void * ptr)781 ralloc_parent_of_linear_parent(void *ptr)
782 {
783    linear_header *node = LINEAR_PARENT_TO_HEADER(ptr);
784    assert(node->magic == LMAGIC);
785    return node->ralloc_parent;
786 }
787 
788 void *
linear_realloc(void * parent,void * old,unsigned new_size)789 linear_realloc(void *parent, void *old, unsigned new_size)
790 {
791    unsigned old_size = 0;
792    ralloc_header *new_ptr;
793 
794    new_ptr = linear_alloc_child(parent, new_size);
795 
796    if (unlikely(!old))
797       return new_ptr;
798 
799    old_size = ((linear_size_chunk*)old)[-1].size;
800 
801    if (likely(new_ptr && old_size))
802       memcpy(new_ptr, old, MIN2(old_size, new_size));
803 
804    return new_ptr;
805 }
806 
807 /* All code below is pretty much copied from ralloc and only the alloc
808  * calls are different.
809  */
810 
811 char *
linear_strdup(void * parent,const char * str)812 linear_strdup(void *parent, const char *str)
813 {
814    unsigned n;
815    char *ptr;
816 
817    if (unlikely(!str))
818       return NULL;
819 
820    n = strlen(str);
821    ptr = linear_alloc_child(parent, n + 1);
822    if (unlikely(!ptr))
823       return NULL;
824 
825    memcpy(ptr, str, n);
826    ptr[n] = '\0';
827    return ptr;
828 }
829 
830 char *
linear_asprintf(void * parent,const char * fmt,...)831 linear_asprintf(void *parent, const char *fmt, ...)
832 {
833    char *ptr;
834    va_list args;
835    va_start(args, fmt);
836    ptr = linear_vasprintf(parent, fmt, args);
837    va_end(args);
838    return ptr;
839 }
840 
841 char *
linear_vasprintf(void * parent,const char * fmt,va_list args)842 linear_vasprintf(void *parent, const char *fmt, va_list args)
843 {
844    unsigned size = printf_length(fmt, args) + 1;
845 
846    char *ptr = linear_alloc_child(parent, size);
847    if (ptr != NULL)
848       vsnprintf(ptr, size, fmt, args);
849 
850    return ptr;
851 }
852 
853 bool
linear_asprintf_append(void * parent,char ** str,const char * fmt,...)854 linear_asprintf_append(void *parent, char **str, const char *fmt, ...)
855 {
856    bool success;
857    va_list args;
858    va_start(args, fmt);
859    success = linear_vasprintf_append(parent, str, fmt, args);
860    va_end(args);
861    return success;
862 }
863 
864 bool
linear_vasprintf_append(void * parent,char ** str,const char * fmt,va_list args)865 linear_vasprintf_append(void *parent, char **str, const char *fmt, va_list args)
866 {
867    size_t existing_length;
868    assert(str != NULL);
869    existing_length = *str ? strlen(*str) : 0;
870    return linear_vasprintf_rewrite_tail(parent, str, &existing_length, fmt, args);
871 }
872 
873 bool
linear_asprintf_rewrite_tail(void * parent,char ** str,size_t * start,const char * fmt,...)874 linear_asprintf_rewrite_tail(void *parent, char **str, size_t *start,
875                              const char *fmt, ...)
876 {
877    bool success;
878    va_list args;
879    va_start(args, fmt);
880    success = linear_vasprintf_rewrite_tail(parent, str, start, fmt, args);
881    va_end(args);
882    return success;
883 }
884 
885 bool
linear_vasprintf_rewrite_tail(void * parent,char ** str,size_t * start,const char * fmt,va_list args)886 linear_vasprintf_rewrite_tail(void *parent, char **str, size_t *start,
887                               const char *fmt, va_list args)
888 {
889    size_t new_length;
890    char *ptr;
891 
892    assert(str != NULL);
893 
894    if (unlikely(*str == NULL)) {
895       *str = linear_vasprintf(parent, fmt, args);
896       *start = strlen(*str);
897       return true;
898    }
899 
900    new_length = printf_length(fmt, args);
901 
902    ptr = linear_realloc(parent, *str, *start + new_length + 1);
903    if (unlikely(ptr == NULL))
904       return false;
905 
906    vsnprintf(ptr + *start, new_length + 1, fmt, args);
907    *str = ptr;
908    *start += new_length;
909    return true;
910 }
911 
912 /* helper routine for strcat/strncat - n is the exact amount to copy */
913 static bool
linear_cat(void * parent,char ** dest,const char * str,unsigned n)914 linear_cat(void *parent, char **dest, const char *str, unsigned n)
915 {
916    char *both;
917    unsigned existing_length;
918    assert(dest != NULL && *dest != NULL);
919 
920    existing_length = strlen(*dest);
921    both = linear_realloc(parent, *dest, existing_length + n + 1);
922    if (unlikely(both == NULL))
923       return false;
924 
925    memcpy(both + existing_length, str, n);
926    both[existing_length + n] = '\0';
927 
928    *dest = both;
929    return true;
930 }
931 
932 bool
linear_strcat(void * parent,char ** dest,const char * str)933 linear_strcat(void *parent, char **dest, const char *str)
934 {
935    return linear_cat(parent, dest, str, strlen(str));
936 }
937