Home | History | Annotate | Download | only in compiler
      1 /*
      2  * Copyright  2014 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 DEALINGS
     21  * IN THE SOFTWARE.
     22  */
     23 
     24 #include <string.h>
     25 
     26 #include "main/macros.h"
     27 #include "blob.h"
     28 
     29 #ifdef HAVE_VALGRIND
     30 #include <valgrind.h>
     31 #include <memcheck.h>
     32 #define VG(x) x
     33 #else
     34 #define VG(x)
     35 #endif
     36 
     37 #define BLOB_INITIAL_SIZE 4096
     38 
     39 /* Ensure that \blob will be able to fit an additional object of size
     40  * \additional.  The growing (if any) will occur by doubling the existing
     41  * allocation.
     42  */
     43 static bool
     44 grow_to_fit(struct blob *blob, size_t additional)
     45 {
     46    size_t to_allocate;
     47    uint8_t *new_data;
     48 
     49    if (blob->out_of_memory)
     50       return false;
     51 
     52    if (blob->size + additional <= blob->allocated)
     53       return true;
     54 
     55    if (blob->fixed_allocation) {
     56       blob->out_of_memory = true;
     57       return false;
     58    }
     59 
     60    if (blob->allocated == 0)
     61       to_allocate = BLOB_INITIAL_SIZE;
     62    else
     63       to_allocate = blob->allocated * 2;
     64 
     65    to_allocate = MAX2(to_allocate, blob->allocated + additional);
     66 
     67    new_data = realloc(blob->data, to_allocate);
     68    if (new_data == NULL) {
     69       blob->out_of_memory = true;
     70       return false;
     71    }
     72 
     73    blob->data = new_data;
     74    blob->allocated = to_allocate;
     75 
     76    return true;
     77 }
     78 
     79 /* Align the blob->size so that reading or writing a value at (blob->data +
     80  * blob->size) will result in an access aligned to a granularity of \alignment
     81  * bytes.
     82  *
     83  * \return True unless allocation fails
     84  */
     85 static bool
     86 align_blob(struct blob *blob, size_t alignment)
     87 {
     88    const size_t new_size = ALIGN(blob->size, alignment);
     89 
     90    if (blob->size < new_size) {
     91       if (!grow_to_fit(blob, new_size - blob->size))
     92          return false;
     93 
     94       if (blob->data)
     95          memset(blob->data + blob->size, 0, new_size - blob->size);
     96       blob->size = new_size;
     97    }
     98 
     99    return true;
    100 }
    101 
    102 static void
    103 align_blob_reader(struct blob_reader *blob, size_t alignment)
    104 {
    105    blob->current = blob->data + ALIGN(blob->current - blob->data, alignment);
    106 }
    107 
    108 void
    109 blob_init(struct blob *blob)
    110 {
    111    blob->data = NULL;
    112    blob->allocated = 0;
    113    blob->size = 0;
    114    blob->fixed_allocation = false;
    115    blob->out_of_memory = false;
    116 }
    117 
    118 void
    119 blob_init_fixed(struct blob *blob, void *data, size_t size)
    120 {
    121    blob->data = data;
    122    blob->allocated = size;
    123    blob->size = 0;
    124    blob->fixed_allocation = true;
    125    blob->out_of_memory = false;
    126 }
    127 
    128 bool
    129 blob_overwrite_bytes(struct blob *blob,
    130                      size_t offset,
    131                      const void *bytes,
    132                      size_t to_write)
    133 {
    134    /* Detect an attempt to overwrite data out of bounds. */
    135    if (offset + to_write < offset || blob->size < offset + to_write)
    136       return false;
    137 
    138    VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write));
    139 
    140    if (blob->data)
    141       memcpy(blob->data + offset, bytes, to_write);
    142 
    143    return true;
    144 }
    145 
    146 bool
    147 blob_write_bytes(struct blob *blob, const void *bytes, size_t to_write)
    148 {
    149    if (! grow_to_fit(blob, to_write))
    150        return false;
    151 
    152    VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write));
    153 
    154    if (blob->data)
    155       memcpy(blob->data + blob->size, bytes, to_write);
    156    blob->size += to_write;
    157 
    158    return true;
    159 }
    160 
    161 intptr_t
    162 blob_reserve_bytes(struct blob *blob, size_t to_write)
    163 {
    164    intptr_t ret;
    165 
    166    if (! grow_to_fit (blob, to_write))
    167       return -1;
    168 
    169    ret = blob->size;
    170    blob->size += to_write;
    171 
    172    return ret;
    173 }
    174 
    175 intptr_t
    176 blob_reserve_uint32(struct blob *blob)
    177 {
    178    align_blob(blob, sizeof(uint32_t));
    179    return blob_reserve_bytes(blob, sizeof(uint32_t));
    180 }
    181 
    182 intptr_t
    183 blob_reserve_intptr(struct blob *blob)
    184 {
    185    align_blob(blob, sizeof(intptr_t));
    186    return blob_reserve_bytes(blob, sizeof(intptr_t));
    187 }
    188 
    189 bool
    190 blob_write_uint32(struct blob *blob, uint32_t value)
    191 {
    192    align_blob(blob, sizeof(value));
    193 
    194    return blob_write_bytes(blob, &value, sizeof(value));
    195 }
    196 
    197 #define ASSERT_ALIGNED(_offset, _align) \
    198    assert(ALIGN((_offset), (_align)) == (_offset))
    199 
    200 bool
    201 blob_overwrite_uint32 (struct blob *blob,
    202                        size_t offset,
    203                        uint32_t value)
    204 {
    205    ASSERT_ALIGNED(offset, sizeof(value));
    206    return blob_overwrite_bytes(blob, offset, &value, sizeof(value));
    207 }
    208 
    209 bool
    210 blob_write_uint64(struct blob *blob, uint64_t value)
    211 {
    212    align_blob(blob, sizeof(value));
    213 
    214    return blob_write_bytes(blob, &value, sizeof(value));
    215 }
    216 
    217 bool
    218 blob_write_intptr(struct blob *blob, intptr_t value)
    219 {
    220    align_blob(blob, sizeof(value));
    221 
    222    return blob_write_bytes(blob, &value, sizeof(value));
    223 }
    224 
    225 bool
    226 blob_overwrite_intptr (struct blob *blob,
    227                        size_t offset,
    228                        intptr_t value)
    229 {
    230    ASSERT_ALIGNED(offset, sizeof(value));
    231    return blob_overwrite_bytes(blob, offset, &value, sizeof(value));
    232 }
    233 
    234 bool
    235 blob_write_string(struct blob *blob, const char *str)
    236 {
    237    return blob_write_bytes(blob, str, strlen(str) + 1);
    238 }
    239 
    240 void
    241 blob_reader_init(struct blob_reader *blob, const void *data, size_t size)
    242 {
    243    blob->data = data;
    244    blob->end = blob->data + size;
    245    blob->current = data;
    246    blob->overrun = false;
    247 }
    248 
    249 /* Check that an object of size \size can be read from this blob.
    250  *
    251  * If not, set blob->overrun to indicate that we attempted to read too far.
    252  */
    253 static bool
    254 ensure_can_read(struct blob_reader *blob, size_t size)
    255 {
    256    if (blob->overrun)
    257       return false;
    258 
    259    if (blob->current <= blob->end && blob->end - blob->current >= size)
    260       return true;
    261 
    262    blob->overrun = true;
    263 
    264    return false;
    265 }
    266 
    267 const void *
    268 blob_read_bytes(struct blob_reader *blob, size_t size)
    269 {
    270    const void *ret;
    271 
    272    if (! ensure_can_read (blob, size))
    273       return NULL;
    274 
    275    ret = blob->current;
    276 
    277    blob->current += size;
    278 
    279    return ret;
    280 }
    281 
    282 void
    283 blob_copy_bytes(struct blob_reader *blob, void *dest, size_t size)
    284 {
    285    const void *bytes;
    286 
    287    bytes = blob_read_bytes(blob, size);
    288    if (bytes == NULL)
    289       return;
    290 
    291    memcpy(dest, bytes, size);
    292 }
    293 
    294 /* These next three read functions have identical form. If we add any beyond
    295  * these first three we should probably switch to generating these with a
    296  * preprocessor macro.
    297 */
    298 uint32_t
    299 blob_read_uint32(struct blob_reader *blob)
    300 {
    301    uint32_t ret;
    302    int size = sizeof(ret);
    303 
    304    align_blob_reader(blob, size);
    305 
    306    if (! ensure_can_read(blob, size))
    307       return 0;
    308 
    309    ret = *((uint32_t*) blob->current);
    310 
    311    blob->current += size;
    312 
    313    return ret;
    314 }
    315 
    316 uint64_t
    317 blob_read_uint64(struct blob_reader *blob)
    318 {
    319    uint64_t ret;
    320    int size = sizeof(ret);
    321 
    322    align_blob_reader(blob, size);
    323 
    324    if (! ensure_can_read(blob, size))
    325       return 0;
    326 
    327    ret = *((uint64_t*) blob->current);
    328 
    329    blob->current += size;
    330 
    331    return ret;
    332 }
    333 
    334 intptr_t
    335 blob_read_intptr(struct blob_reader *blob)
    336 {
    337    intptr_t ret;
    338    int size = sizeof(ret);
    339 
    340    align_blob_reader(blob, size);
    341 
    342    if (! ensure_can_read(blob, size))
    343       return 0;
    344 
    345    ret = *((intptr_t *) blob->current);
    346 
    347    blob->current += size;
    348 
    349    return ret;
    350 }
    351 
    352 char *
    353 blob_read_string(struct blob_reader *blob)
    354 {
    355    int size;
    356    char *ret;
    357    uint8_t *nul;
    358 
    359    /* If we're already at the end, then this is an overrun. */
    360    if (blob->current >= blob->end) {
    361       blob->overrun = true;
    362       return NULL;
    363    }
    364 
    365    /* Similarly, if there is no zero byte in the data remaining in this blob,
    366     * we also consider that an overrun.
    367     */
    368    nul = memchr(blob->current, 0, blob->end - blob->current);
    369 
    370    if (nul == NULL) {
    371       blob->overrun = true;
    372       return NULL;
    373    }
    374 
    375    size = nul - blob->current + 1;
    376 
    377    assert(ensure_can_read(blob, size));
    378 
    379    ret = (char *) blob->current;
    380 
    381    blob->current += size;
    382 
    383    return ret;
    384 }
    385