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