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