17ec681f3Smrg/* 27ec681f3Smrg * Copyright © 2014 Intel Corporation 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 217ec681f3Smrg * IN THE SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#include <string.h> 257ec681f3Smrg 267ec681f3Smrg#include "blob.h" 277ec681f3Smrg#include "u_math.h" 287ec681f3Smrg 297ec681f3Smrg#ifdef HAVE_VALGRIND 307ec681f3Smrg#include <valgrind.h> 317ec681f3Smrg#include <memcheck.h> 327ec681f3Smrg#define VG(x) x 337ec681f3Smrg#else 347ec681f3Smrg#define VG(x) 357ec681f3Smrg#endif 367ec681f3Smrg 377ec681f3Smrg#define BLOB_INITIAL_SIZE 4096 387ec681f3Smrg 397ec681f3Smrg/* Ensure that \blob will be able to fit an additional object of size 407ec681f3Smrg * \additional. The growing (if any) will occur by doubling the existing 417ec681f3Smrg * allocation. 427ec681f3Smrg */ 437ec681f3Smrgstatic bool 447ec681f3Smrggrow_to_fit(struct blob *blob, size_t additional) 457ec681f3Smrg{ 467ec681f3Smrg size_t to_allocate; 477ec681f3Smrg uint8_t *new_data; 487ec681f3Smrg 497ec681f3Smrg if (blob->out_of_memory) 507ec681f3Smrg return false; 517ec681f3Smrg 527ec681f3Smrg if (blob->size + additional <= blob->allocated) 537ec681f3Smrg return true; 547ec681f3Smrg 557ec681f3Smrg if (blob->fixed_allocation) { 567ec681f3Smrg blob->out_of_memory = true; 577ec681f3Smrg return false; 587ec681f3Smrg } 597ec681f3Smrg 607ec681f3Smrg if (blob->allocated == 0) 617ec681f3Smrg to_allocate = BLOB_INITIAL_SIZE; 627ec681f3Smrg else 637ec681f3Smrg to_allocate = blob->allocated * 2; 647ec681f3Smrg 657ec681f3Smrg to_allocate = MAX2(to_allocate, blob->allocated + additional); 667ec681f3Smrg 677ec681f3Smrg new_data = realloc(blob->data, to_allocate); 687ec681f3Smrg if (new_data == NULL) { 697ec681f3Smrg blob->out_of_memory = true; 707ec681f3Smrg return false; 717ec681f3Smrg } 727ec681f3Smrg 737ec681f3Smrg blob->data = new_data; 747ec681f3Smrg blob->allocated = to_allocate; 757ec681f3Smrg 767ec681f3Smrg return true; 777ec681f3Smrg} 787ec681f3Smrg 797ec681f3Smrg/* Align the blob->size so that reading or writing a value at (blob->data + 807ec681f3Smrg * blob->size) will result in an access aligned to a granularity of \alignment 817ec681f3Smrg * bytes. 827ec681f3Smrg * 837ec681f3Smrg * \return True unless allocation fails 847ec681f3Smrg */ 857ec681f3Smrgstatic bool 867ec681f3Smrgalign_blob(struct blob *blob, size_t alignment) 877ec681f3Smrg{ 887ec681f3Smrg const size_t new_size = align64(blob->size, alignment); 897ec681f3Smrg 907ec681f3Smrg if (blob->size < new_size) { 917ec681f3Smrg if (!grow_to_fit(blob, new_size - blob->size)) 927ec681f3Smrg return false; 937ec681f3Smrg 947ec681f3Smrg if (blob->data) 957ec681f3Smrg memset(blob->data + blob->size, 0, new_size - blob->size); 967ec681f3Smrg blob->size = new_size; 977ec681f3Smrg } 987ec681f3Smrg 997ec681f3Smrg return true; 1007ec681f3Smrg} 1017ec681f3Smrg 1027ec681f3Smrgstatic void 1037ec681f3Smrgalign_blob_reader(struct blob_reader *blob, size_t alignment) 1047ec681f3Smrg{ 1057ec681f3Smrg blob->current = blob->data + align64(blob->current - blob->data, alignment); 1067ec681f3Smrg} 1077ec681f3Smrg 1087ec681f3Smrgvoid 1097ec681f3Smrgblob_init(struct blob *blob) 1107ec681f3Smrg{ 1117ec681f3Smrg blob->data = NULL; 1127ec681f3Smrg blob->allocated = 0; 1137ec681f3Smrg blob->size = 0; 1147ec681f3Smrg blob->fixed_allocation = false; 1157ec681f3Smrg blob->out_of_memory = false; 1167ec681f3Smrg} 1177ec681f3Smrg 1187ec681f3Smrgvoid 1197ec681f3Smrgblob_init_fixed(struct blob *blob, void *data, size_t size) 1207ec681f3Smrg{ 1217ec681f3Smrg blob->data = data; 1227ec681f3Smrg blob->allocated = size; 1237ec681f3Smrg blob->size = 0; 1247ec681f3Smrg blob->fixed_allocation = true; 1257ec681f3Smrg blob->out_of_memory = false; 1267ec681f3Smrg} 1277ec681f3Smrg 1287ec681f3Smrgvoid 1297ec681f3Smrgblob_finish_get_buffer(struct blob *blob, void **buffer, size_t *size) 1307ec681f3Smrg{ 1317ec681f3Smrg *buffer = blob->data; 1327ec681f3Smrg *size = blob->size; 1337ec681f3Smrg blob->data = NULL; 1347ec681f3Smrg 1357ec681f3Smrg /* Trim the buffer. */ 1367ec681f3Smrg *buffer = realloc(*buffer, *size); 1377ec681f3Smrg} 1387ec681f3Smrg 1397ec681f3Smrgbool 1407ec681f3Smrgblob_overwrite_bytes(struct blob *blob, 1417ec681f3Smrg size_t offset, 1427ec681f3Smrg const void *bytes, 1437ec681f3Smrg size_t to_write) 1447ec681f3Smrg{ 1457ec681f3Smrg /* Detect an attempt to overwrite data out of bounds. */ 1467ec681f3Smrg if (offset + to_write < offset || blob->size < offset + to_write) 1477ec681f3Smrg return false; 1487ec681f3Smrg 1497ec681f3Smrg VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write)); 1507ec681f3Smrg 1517ec681f3Smrg if (blob->data) 1527ec681f3Smrg memcpy(blob->data + offset, bytes, to_write); 1537ec681f3Smrg 1547ec681f3Smrg return true; 1557ec681f3Smrg} 1567ec681f3Smrg 1577ec681f3Smrgbool 1587ec681f3Smrgblob_write_bytes(struct blob *blob, const void *bytes, size_t to_write) 1597ec681f3Smrg{ 1607ec681f3Smrg if (! grow_to_fit(blob, to_write)) 1617ec681f3Smrg return false; 1627ec681f3Smrg 1637ec681f3Smrg VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write)); 1647ec681f3Smrg 1657ec681f3Smrg if (blob->data && to_write > 0) 1667ec681f3Smrg memcpy(blob->data + blob->size, bytes, to_write); 1677ec681f3Smrg blob->size += to_write; 1687ec681f3Smrg 1697ec681f3Smrg return true; 1707ec681f3Smrg} 1717ec681f3Smrg 1727ec681f3Smrgintptr_t 1737ec681f3Smrgblob_reserve_bytes(struct blob *blob, size_t to_write) 1747ec681f3Smrg{ 1757ec681f3Smrg intptr_t ret; 1767ec681f3Smrg 1777ec681f3Smrg if (! grow_to_fit (blob, to_write)) 1787ec681f3Smrg return -1; 1797ec681f3Smrg 1807ec681f3Smrg ret = blob->size; 1817ec681f3Smrg blob->size += to_write; 1827ec681f3Smrg 1837ec681f3Smrg return ret; 1847ec681f3Smrg} 1857ec681f3Smrg 1867ec681f3Smrgintptr_t 1877ec681f3Smrgblob_reserve_uint32(struct blob *blob) 1887ec681f3Smrg{ 1897ec681f3Smrg align_blob(blob, sizeof(uint32_t)); 1907ec681f3Smrg return blob_reserve_bytes(blob, sizeof(uint32_t)); 1917ec681f3Smrg} 1927ec681f3Smrg 1937ec681f3Smrgintptr_t 1947ec681f3Smrgblob_reserve_intptr(struct blob *blob) 1957ec681f3Smrg{ 1967ec681f3Smrg align_blob(blob, sizeof(intptr_t)); 1977ec681f3Smrg return blob_reserve_bytes(blob, sizeof(intptr_t)); 1987ec681f3Smrg} 1997ec681f3Smrg 2007ec681f3Smrg#define BLOB_WRITE_TYPE(name, type) \ 2017ec681f3Smrgbool \ 2027ec681f3Smrgname(struct blob *blob, type value) \ 2037ec681f3Smrg{ \ 2047ec681f3Smrg align_blob(blob, sizeof(value)); \ 2057ec681f3Smrg return blob_write_bytes(blob, &value, sizeof(value)); \ 2067ec681f3Smrg} 2077ec681f3Smrg 2087ec681f3SmrgBLOB_WRITE_TYPE(blob_write_uint8, uint8_t) 2097ec681f3SmrgBLOB_WRITE_TYPE(blob_write_uint16, uint16_t) 2107ec681f3SmrgBLOB_WRITE_TYPE(blob_write_uint32, uint32_t) 2117ec681f3SmrgBLOB_WRITE_TYPE(blob_write_uint64, uint64_t) 2127ec681f3SmrgBLOB_WRITE_TYPE(blob_write_intptr, intptr_t) 2137ec681f3Smrg 2147ec681f3Smrg#define ASSERT_ALIGNED(_offset, _align) \ 2157ec681f3Smrg assert(align64((_offset), (_align)) == (_offset)) 2167ec681f3Smrg 2177ec681f3Smrgbool 2187ec681f3Smrgblob_overwrite_uint8 (struct blob *blob, 2197ec681f3Smrg size_t offset, 2207ec681f3Smrg uint8_t value) 2217ec681f3Smrg{ 2227ec681f3Smrg ASSERT_ALIGNED(offset, sizeof(value)); 2237ec681f3Smrg return blob_overwrite_bytes(blob, offset, &value, sizeof(value)); 2247ec681f3Smrg} 2257ec681f3Smrg 2267ec681f3Smrgbool 2277ec681f3Smrgblob_overwrite_uint32 (struct blob *blob, 2287ec681f3Smrg size_t offset, 2297ec681f3Smrg uint32_t value) 2307ec681f3Smrg{ 2317ec681f3Smrg ASSERT_ALIGNED(offset, sizeof(value)); 2327ec681f3Smrg return blob_overwrite_bytes(blob, offset, &value, sizeof(value)); 2337ec681f3Smrg} 2347ec681f3Smrg 2357ec681f3Smrgbool 2367ec681f3Smrgblob_overwrite_intptr (struct blob *blob, 2377ec681f3Smrg size_t offset, 2387ec681f3Smrg intptr_t value) 2397ec681f3Smrg{ 2407ec681f3Smrg ASSERT_ALIGNED(offset, sizeof(value)); 2417ec681f3Smrg return blob_overwrite_bytes(blob, offset, &value, sizeof(value)); 2427ec681f3Smrg} 2437ec681f3Smrg 2447ec681f3Smrgbool 2457ec681f3Smrgblob_write_string(struct blob *blob, const char *str) 2467ec681f3Smrg{ 2477ec681f3Smrg return blob_write_bytes(blob, str, strlen(str) + 1); 2487ec681f3Smrg} 2497ec681f3Smrg 2507ec681f3Smrgvoid 2517ec681f3Smrgblob_reader_init(struct blob_reader *blob, const void *data, size_t size) 2527ec681f3Smrg{ 2537ec681f3Smrg blob->data = data; 2547ec681f3Smrg blob->end = blob->data + size; 2557ec681f3Smrg blob->current = data; 2567ec681f3Smrg blob->overrun = false; 2577ec681f3Smrg} 2587ec681f3Smrg 2597ec681f3Smrg/* Check that an object of size \size can be read from this blob. 2607ec681f3Smrg * 2617ec681f3Smrg * If not, set blob->overrun to indicate that we attempted to read too far. 2627ec681f3Smrg */ 2637ec681f3Smrgstatic bool 2647ec681f3Smrgensure_can_read(struct blob_reader *blob, size_t size) 2657ec681f3Smrg{ 2667ec681f3Smrg if (blob->overrun) 2677ec681f3Smrg return false; 2687ec681f3Smrg 2697ec681f3Smrg if (blob->current <= blob->end && blob->end - blob->current >= size) 2707ec681f3Smrg return true; 2717ec681f3Smrg 2727ec681f3Smrg blob->overrun = true; 2737ec681f3Smrg 2747ec681f3Smrg return false; 2757ec681f3Smrg} 2767ec681f3Smrg 2777ec681f3Smrgconst void * 2787ec681f3Smrgblob_read_bytes(struct blob_reader *blob, size_t size) 2797ec681f3Smrg{ 2807ec681f3Smrg const void *ret; 2817ec681f3Smrg 2827ec681f3Smrg if (! ensure_can_read (blob, size)) 2837ec681f3Smrg return NULL; 2847ec681f3Smrg 2857ec681f3Smrg ret = blob->current; 2867ec681f3Smrg 2877ec681f3Smrg blob->current += size; 2887ec681f3Smrg 2897ec681f3Smrg return ret; 2907ec681f3Smrg} 2917ec681f3Smrg 2927ec681f3Smrgvoid 2937ec681f3Smrgblob_copy_bytes(struct blob_reader *blob, void *dest, size_t size) 2947ec681f3Smrg{ 2957ec681f3Smrg const void *bytes; 2967ec681f3Smrg 2977ec681f3Smrg bytes = blob_read_bytes(blob, size); 2987ec681f3Smrg if (bytes == NULL || size == 0) 2997ec681f3Smrg return; 3007ec681f3Smrg 3017ec681f3Smrg memcpy(dest, bytes, size); 3027ec681f3Smrg} 3037ec681f3Smrg 3047ec681f3Smrgvoid 3057ec681f3Smrgblob_skip_bytes(struct blob_reader *blob, size_t size) 3067ec681f3Smrg{ 3077ec681f3Smrg if (ensure_can_read (blob, size)) 3087ec681f3Smrg blob->current += size; 3097ec681f3Smrg} 3107ec681f3Smrg 3117ec681f3Smrg/* These next three read functions have identical form. If we add any beyond 3127ec681f3Smrg * these first three we should probably switch to generating these with a 3137ec681f3Smrg * preprocessor macro. 3147ec681f3Smrg*/ 3157ec681f3Smrg 3167ec681f3Smrg#define BLOB_READ_TYPE(name, type) \ 3177ec681f3Smrgtype \ 3187ec681f3Smrgname(struct blob_reader *blob) \ 3197ec681f3Smrg{ \ 3207ec681f3Smrg type ret; \ 3217ec681f3Smrg int size = sizeof(ret); \ 3227ec681f3Smrg align_blob_reader(blob, size); \ 3237ec681f3Smrg if (! ensure_can_read(blob, size)) \ 3247ec681f3Smrg return 0; \ 3257ec681f3Smrg ret = *((type*) blob->current); \ 3267ec681f3Smrg blob->current += size; \ 3277ec681f3Smrg return ret; \ 3287ec681f3Smrg} 3297ec681f3Smrg 3307ec681f3SmrgBLOB_READ_TYPE(blob_read_uint8, uint8_t) 3317ec681f3SmrgBLOB_READ_TYPE(blob_read_uint16, uint16_t) 3327ec681f3SmrgBLOB_READ_TYPE(blob_read_uint32, uint32_t) 3337ec681f3SmrgBLOB_READ_TYPE(blob_read_uint64, uint64_t) 3347ec681f3SmrgBLOB_READ_TYPE(blob_read_intptr, intptr_t) 3357ec681f3Smrg 3367ec681f3Smrgchar * 3377ec681f3Smrgblob_read_string(struct blob_reader *blob) 3387ec681f3Smrg{ 3397ec681f3Smrg int size; 3407ec681f3Smrg char *ret; 3417ec681f3Smrg uint8_t *nul; 3427ec681f3Smrg 3437ec681f3Smrg /* If we're already at the end, then this is an overrun. */ 3447ec681f3Smrg if (blob->current >= blob->end) { 3457ec681f3Smrg blob->overrun = true; 3467ec681f3Smrg return NULL; 3477ec681f3Smrg } 3487ec681f3Smrg 3497ec681f3Smrg /* Similarly, if there is no zero byte in the data remaining in this blob, 3507ec681f3Smrg * we also consider that an overrun. 3517ec681f3Smrg */ 3527ec681f3Smrg nul = memchr(blob->current, 0, blob->end - blob->current); 3537ec681f3Smrg 3547ec681f3Smrg if (nul == NULL) { 3557ec681f3Smrg blob->overrun = true; 3567ec681f3Smrg return NULL; 3577ec681f3Smrg } 3587ec681f3Smrg 3597ec681f3Smrg size = nul - blob->current + 1; 3607ec681f3Smrg 3617ec681f3Smrg assert(ensure_can_read(blob, size)); 3627ec681f3Smrg 3637ec681f3Smrg ret = (char *) blob->current; 3647ec681f3Smrg 3657ec681f3Smrg blob->current += size; 3667ec681f3Smrg 3677ec681f3Smrg return ret; 3687ec681f3Smrg} 369