• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
grow_to_fit(struct blob * blob,size_t additional)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
align_blob(struct blob * blob,size_t alignment)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
align_blob_reader(struct blob_reader * blob,size_t alignment)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
blob_init(struct blob * blob)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
blob_init_fixed(struct blob * blob,void * data,size_t size)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
blob_overwrite_bytes(struct blob * blob,size_t offset,const void * bytes,size_t to_write)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
blob_write_bytes(struct blob * blob,const void * bytes,size_t to_write)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
blob_reserve_bytes(struct blob * blob,size_t to_write)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
blob_reserve_uint32(struct blob * blob)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
blob_reserve_intptr(struct blob * blob)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
blob_write_uint32(struct blob * blob,uint32_t value)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
blob_overwrite_uint32(struct blob * blob,size_t offset,uint32_t value)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
blob_write_uint64(struct blob * blob,uint64_t value)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
blob_write_intptr(struct blob * blob,intptr_t value)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
blob_overwrite_intptr(struct blob * blob,size_t offset,intptr_t value)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
blob_write_string(struct blob * blob,const char * str)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
blob_reader_init(struct blob_reader * blob,const void * data,size_t size)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
ensure_can_read(struct blob_reader * blob,size_t size)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 *
blob_read_bytes(struct blob_reader * blob,size_t size)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
blob_copy_bytes(struct blob_reader * blob,void * dest,size_t size)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
blob_read_uint32(struct blob_reader * blob)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
blob_read_uint64(struct blob_reader * blob)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
blob_read_intptr(struct blob_reader * blob)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 *
blob_read_string(struct blob_reader * blob)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