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