1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2014 Intel Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include <string.h> 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "blob.h" 27bf215546Sopenharmony_ci#include "u_math.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#ifdef HAVE_VALGRIND 30bf215546Sopenharmony_ci#include <valgrind.h> 31bf215546Sopenharmony_ci#include <memcheck.h> 32bf215546Sopenharmony_ci#define VG(x) x 33bf215546Sopenharmony_ci#else 34bf215546Sopenharmony_ci#define VG(x) 35bf215546Sopenharmony_ci#endif 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci#define BLOB_INITIAL_SIZE 4096 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci/* Ensure that \blob will be able to fit an additional object of size 40bf215546Sopenharmony_ci * \additional. The growing (if any) will occur by doubling the existing 41bf215546Sopenharmony_ci * allocation. 42bf215546Sopenharmony_ci */ 43bf215546Sopenharmony_cistatic bool 44bf215546Sopenharmony_cigrow_to_fit(struct blob *blob, size_t additional) 45bf215546Sopenharmony_ci{ 46bf215546Sopenharmony_ci size_t to_allocate; 47bf215546Sopenharmony_ci uint8_t *new_data; 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_ci if (blob->out_of_memory) 50bf215546Sopenharmony_ci return false; 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci if (blob->size + additional <= blob->allocated) 53bf215546Sopenharmony_ci return true; 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci if (blob->fixed_allocation) { 56bf215546Sopenharmony_ci blob->out_of_memory = true; 57bf215546Sopenharmony_ci return false; 58bf215546Sopenharmony_ci } 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci if (blob->allocated == 0) 61bf215546Sopenharmony_ci to_allocate = BLOB_INITIAL_SIZE; 62bf215546Sopenharmony_ci else 63bf215546Sopenharmony_ci to_allocate = blob->allocated * 2; 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci to_allocate = MAX2(to_allocate, blob->allocated + additional); 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci new_data = realloc(blob->data, to_allocate); 68bf215546Sopenharmony_ci if (new_data == NULL) { 69bf215546Sopenharmony_ci blob->out_of_memory = true; 70bf215546Sopenharmony_ci return false; 71bf215546Sopenharmony_ci } 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci blob->data = new_data; 74bf215546Sopenharmony_ci blob->allocated = to_allocate; 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci return true; 77bf215546Sopenharmony_ci} 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci/* Align the blob->size so that reading or writing a value at (blob->data + 80bf215546Sopenharmony_ci * blob->size) will result in an access aligned to a granularity of \alignment 81bf215546Sopenharmony_ci * bytes. 82bf215546Sopenharmony_ci * 83bf215546Sopenharmony_ci * \return True unless allocation fails 84bf215546Sopenharmony_ci */ 85bf215546Sopenharmony_cibool 86bf215546Sopenharmony_ciblob_align(struct blob *blob, size_t alignment) 87bf215546Sopenharmony_ci{ 88bf215546Sopenharmony_ci const size_t new_size = align64(blob->size, alignment); 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci if (blob->size < new_size) { 91bf215546Sopenharmony_ci if (!grow_to_fit(blob, new_size - blob->size)) 92bf215546Sopenharmony_ci return false; 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci if (blob->data) 95bf215546Sopenharmony_ci memset(blob->data + blob->size, 0, new_size - blob->size); 96bf215546Sopenharmony_ci blob->size = new_size; 97bf215546Sopenharmony_ci } 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci return true; 100bf215546Sopenharmony_ci} 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_civoid 103bf215546Sopenharmony_ciblob_reader_align(struct blob_reader *blob, size_t alignment) 104bf215546Sopenharmony_ci{ 105bf215546Sopenharmony_ci blob->current = blob->data + align64(blob->current - blob->data, alignment); 106bf215546Sopenharmony_ci} 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_civoid 109bf215546Sopenharmony_ciblob_init(struct blob *blob) 110bf215546Sopenharmony_ci{ 111bf215546Sopenharmony_ci blob->data = NULL; 112bf215546Sopenharmony_ci blob->allocated = 0; 113bf215546Sopenharmony_ci blob->size = 0; 114bf215546Sopenharmony_ci blob->fixed_allocation = false; 115bf215546Sopenharmony_ci blob->out_of_memory = false; 116bf215546Sopenharmony_ci} 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_civoid 119bf215546Sopenharmony_ciblob_init_fixed(struct blob *blob, void *data, size_t size) 120bf215546Sopenharmony_ci{ 121bf215546Sopenharmony_ci blob->data = data; 122bf215546Sopenharmony_ci blob->allocated = size; 123bf215546Sopenharmony_ci blob->size = 0; 124bf215546Sopenharmony_ci blob->fixed_allocation = true; 125bf215546Sopenharmony_ci blob->out_of_memory = false; 126bf215546Sopenharmony_ci} 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_civoid 129bf215546Sopenharmony_ciblob_finish_get_buffer(struct blob *blob, void **buffer, size_t *size) 130bf215546Sopenharmony_ci{ 131bf215546Sopenharmony_ci *buffer = blob->data; 132bf215546Sopenharmony_ci *size = blob->size; 133bf215546Sopenharmony_ci blob->data = NULL; 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci /* Trim the buffer. */ 136bf215546Sopenharmony_ci *buffer = realloc(*buffer, *size); 137bf215546Sopenharmony_ci} 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_cibool 140bf215546Sopenharmony_ciblob_overwrite_bytes(struct blob *blob, 141bf215546Sopenharmony_ci size_t offset, 142bf215546Sopenharmony_ci const void *bytes, 143bf215546Sopenharmony_ci size_t to_write) 144bf215546Sopenharmony_ci{ 145bf215546Sopenharmony_ci /* Detect an attempt to overwrite data out of bounds. */ 146bf215546Sopenharmony_ci if (offset + to_write < offset || blob->size < offset + to_write) 147bf215546Sopenharmony_ci return false; 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write)); 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci if (blob->data) 152bf215546Sopenharmony_ci memcpy(blob->data + offset, bytes, to_write); 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci return true; 155bf215546Sopenharmony_ci} 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_cibool 158bf215546Sopenharmony_ciblob_write_bytes(struct blob *blob, const void *bytes, size_t to_write) 159bf215546Sopenharmony_ci{ 160bf215546Sopenharmony_ci if (! grow_to_fit(blob, to_write)) 161bf215546Sopenharmony_ci return false; 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write)); 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci if (blob->data && to_write > 0) 166bf215546Sopenharmony_ci memcpy(blob->data + blob->size, bytes, to_write); 167bf215546Sopenharmony_ci blob->size += to_write; 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci return true; 170bf215546Sopenharmony_ci} 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ciintptr_t 173bf215546Sopenharmony_ciblob_reserve_bytes(struct blob *blob, size_t to_write) 174bf215546Sopenharmony_ci{ 175bf215546Sopenharmony_ci intptr_t ret; 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci if (! grow_to_fit (blob, to_write)) 178bf215546Sopenharmony_ci return -1; 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci ret = blob->size; 181bf215546Sopenharmony_ci blob->size += to_write; 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_ci return ret; 184bf215546Sopenharmony_ci} 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ciintptr_t 187bf215546Sopenharmony_ciblob_reserve_uint32(struct blob *blob) 188bf215546Sopenharmony_ci{ 189bf215546Sopenharmony_ci blob_align(blob, sizeof(uint32_t)); 190bf215546Sopenharmony_ci return blob_reserve_bytes(blob, sizeof(uint32_t)); 191bf215546Sopenharmony_ci} 192bf215546Sopenharmony_ci 193bf215546Sopenharmony_ciintptr_t 194bf215546Sopenharmony_ciblob_reserve_intptr(struct blob *blob) 195bf215546Sopenharmony_ci{ 196bf215546Sopenharmony_ci blob_align(blob, sizeof(intptr_t)); 197bf215546Sopenharmony_ci return blob_reserve_bytes(blob, sizeof(intptr_t)); 198bf215546Sopenharmony_ci} 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci#define BLOB_WRITE_TYPE(name, type) \ 201bf215546Sopenharmony_cibool \ 202bf215546Sopenharmony_ciname(struct blob *blob, type value) \ 203bf215546Sopenharmony_ci{ \ 204bf215546Sopenharmony_ci blob_align(blob, sizeof(value)); \ 205bf215546Sopenharmony_ci return blob_write_bytes(blob, &value, sizeof(value)); \ 206bf215546Sopenharmony_ci} 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ciBLOB_WRITE_TYPE(blob_write_uint8, uint8_t) 209bf215546Sopenharmony_ciBLOB_WRITE_TYPE(blob_write_uint16, uint16_t) 210bf215546Sopenharmony_ciBLOB_WRITE_TYPE(blob_write_uint32, uint32_t) 211bf215546Sopenharmony_ciBLOB_WRITE_TYPE(blob_write_uint64, uint64_t) 212bf215546Sopenharmony_ciBLOB_WRITE_TYPE(blob_write_intptr, intptr_t) 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci#define ASSERT_ALIGNED(_offset, _align) \ 215bf215546Sopenharmony_ci assert(align64((_offset), (_align)) == (_offset)) 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_cibool 218bf215546Sopenharmony_ciblob_overwrite_uint8 (struct blob *blob, 219bf215546Sopenharmony_ci size_t offset, 220bf215546Sopenharmony_ci uint8_t value) 221bf215546Sopenharmony_ci{ 222bf215546Sopenharmony_ci ASSERT_ALIGNED(offset, sizeof(value)); 223bf215546Sopenharmony_ci return blob_overwrite_bytes(blob, offset, &value, sizeof(value)); 224bf215546Sopenharmony_ci} 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_cibool 227bf215546Sopenharmony_ciblob_overwrite_uint32 (struct blob *blob, 228bf215546Sopenharmony_ci size_t offset, 229bf215546Sopenharmony_ci uint32_t value) 230bf215546Sopenharmony_ci{ 231bf215546Sopenharmony_ci ASSERT_ALIGNED(offset, sizeof(value)); 232bf215546Sopenharmony_ci return blob_overwrite_bytes(blob, offset, &value, sizeof(value)); 233bf215546Sopenharmony_ci} 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_cibool 236bf215546Sopenharmony_ciblob_overwrite_intptr (struct blob *blob, 237bf215546Sopenharmony_ci size_t offset, 238bf215546Sopenharmony_ci intptr_t value) 239bf215546Sopenharmony_ci{ 240bf215546Sopenharmony_ci ASSERT_ALIGNED(offset, sizeof(value)); 241bf215546Sopenharmony_ci return blob_overwrite_bytes(blob, offset, &value, sizeof(value)); 242bf215546Sopenharmony_ci} 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_cibool 245bf215546Sopenharmony_ciblob_write_string(struct blob *blob, const char *str) 246bf215546Sopenharmony_ci{ 247bf215546Sopenharmony_ci return blob_write_bytes(blob, str, strlen(str) + 1); 248bf215546Sopenharmony_ci} 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_civoid 251bf215546Sopenharmony_ciblob_reader_init(struct blob_reader *blob, const void *data, size_t size) 252bf215546Sopenharmony_ci{ 253bf215546Sopenharmony_ci blob->data = data; 254bf215546Sopenharmony_ci blob->end = blob->data + size; 255bf215546Sopenharmony_ci blob->current = data; 256bf215546Sopenharmony_ci blob->overrun = false; 257bf215546Sopenharmony_ci} 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ci/* Check that an object of size \size can be read from this blob. 260bf215546Sopenharmony_ci * 261bf215546Sopenharmony_ci * If not, set blob->overrun to indicate that we attempted to read too far. 262bf215546Sopenharmony_ci */ 263bf215546Sopenharmony_cistatic bool 264bf215546Sopenharmony_ciensure_can_read(struct blob_reader *blob, size_t size) 265bf215546Sopenharmony_ci{ 266bf215546Sopenharmony_ci if (blob->overrun) 267bf215546Sopenharmony_ci return false; 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci if (blob->current <= blob->end && blob->end - blob->current >= size) 270bf215546Sopenharmony_ci return true; 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci blob->overrun = true; 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci return false; 275bf215546Sopenharmony_ci} 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ciconst void * 278bf215546Sopenharmony_ciblob_read_bytes(struct blob_reader *blob, size_t size) 279bf215546Sopenharmony_ci{ 280bf215546Sopenharmony_ci const void *ret; 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci if (! ensure_can_read (blob, size)) 283bf215546Sopenharmony_ci return NULL; 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_ci ret = blob->current; 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci blob->current += size; 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci return ret; 290bf215546Sopenharmony_ci} 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_civoid 293bf215546Sopenharmony_ciblob_copy_bytes(struct blob_reader *blob, void *dest, size_t size) 294bf215546Sopenharmony_ci{ 295bf215546Sopenharmony_ci const void *bytes; 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_ci bytes = blob_read_bytes(blob, size); 298bf215546Sopenharmony_ci if (bytes == NULL || size == 0) 299bf215546Sopenharmony_ci return; 300bf215546Sopenharmony_ci 301bf215546Sopenharmony_ci memcpy(dest, bytes, size); 302bf215546Sopenharmony_ci} 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_civoid 305bf215546Sopenharmony_ciblob_skip_bytes(struct blob_reader *blob, size_t size) 306bf215546Sopenharmony_ci{ 307bf215546Sopenharmony_ci if (ensure_can_read (blob, size)) 308bf215546Sopenharmony_ci blob->current += size; 309bf215546Sopenharmony_ci} 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ci#define BLOB_READ_TYPE(name, type) \ 312bf215546Sopenharmony_citype \ 313bf215546Sopenharmony_ciname(struct blob_reader *blob) \ 314bf215546Sopenharmony_ci{ \ 315bf215546Sopenharmony_ci type ret = 0; \ 316bf215546Sopenharmony_ci int size = sizeof(ret); \ 317bf215546Sopenharmony_ci blob_reader_align(blob, size); \ 318bf215546Sopenharmony_ci blob_copy_bytes(blob, &ret, size); \ 319bf215546Sopenharmony_ci return ret; \ 320bf215546Sopenharmony_ci} 321bf215546Sopenharmony_ci 322bf215546Sopenharmony_ciBLOB_READ_TYPE(blob_read_uint8, uint8_t) 323bf215546Sopenharmony_ciBLOB_READ_TYPE(blob_read_uint16, uint16_t) 324bf215546Sopenharmony_ciBLOB_READ_TYPE(blob_read_uint32, uint32_t) 325bf215546Sopenharmony_ciBLOB_READ_TYPE(blob_read_uint64, uint64_t) 326bf215546Sopenharmony_ciBLOB_READ_TYPE(blob_read_intptr, intptr_t) 327bf215546Sopenharmony_ci 328bf215546Sopenharmony_cichar * 329bf215546Sopenharmony_ciblob_read_string(struct blob_reader *blob) 330bf215546Sopenharmony_ci{ 331bf215546Sopenharmony_ci int size; 332bf215546Sopenharmony_ci char *ret; 333bf215546Sopenharmony_ci uint8_t *nul; 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci /* If we're already at the end, then this is an overrun. */ 336bf215546Sopenharmony_ci if (blob->current >= blob->end) { 337bf215546Sopenharmony_ci blob->overrun = true; 338bf215546Sopenharmony_ci return NULL; 339bf215546Sopenharmony_ci } 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ci /* Similarly, if there is no zero byte in the data remaining in this blob, 342bf215546Sopenharmony_ci * we also consider that an overrun. 343bf215546Sopenharmony_ci */ 344bf215546Sopenharmony_ci nul = memchr(blob->current, 0, blob->end - blob->current); 345bf215546Sopenharmony_ci 346bf215546Sopenharmony_ci if (nul == NULL) { 347bf215546Sopenharmony_ci blob->overrun = true; 348bf215546Sopenharmony_ci return NULL; 349bf215546Sopenharmony_ci } 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_ci size = nul - blob->current + 1; 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ci assert(ensure_can_read(blob, size)); 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_ci ret = (char *) blob->current; 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci blob->current += size; 358bf215546Sopenharmony_ci 359bf215546Sopenharmony_ci return ret; 360bf215546Sopenharmony_ci} 361