2 * Copyright © 2014 Intel Corporation
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:
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
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
26 #include "main/macros.h"
37 #define BLOB_INITIAL_SIZE 4096
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
44 grow_to_fit(struct blob
*blob
, size_t additional
)
49 if (blob
->out_of_memory
)
52 if (blob
->size
+ additional
<= blob
->allocated
)
55 if (blob
->allocated
== 0)
56 to_allocate
= BLOB_INITIAL_SIZE
;
58 to_allocate
= blob
->allocated
* 2;
60 to_allocate
= MAX2(to_allocate
, blob
->allocated
+ additional
);
62 new_data
= realloc(blob
->data
, to_allocate
);
63 if (new_data
== NULL
) {
64 blob
->out_of_memory
= true;
68 blob
->data
= new_data
;
69 blob
->allocated
= to_allocate
;
74 /* Align the blob->size so that reading or writing a value at (blob->data +
75 * blob->size) will result in an access aligned to a granularity of \alignment
78 * \return True unless allocation fails
81 align_blob(struct blob
*blob
, size_t alignment
)
83 const size_t new_size
= ALIGN(blob
->size
, alignment
);
85 if (blob
->size
< new_size
) {
86 if (!grow_to_fit(blob
, new_size
- blob
->size
))
89 memset(blob
->data
+ blob
->size
, 0, new_size
- blob
->size
);
90 blob
->size
= new_size
;
97 align_blob_reader(struct blob_reader
*blob
, size_t alignment
)
99 blob
->current
= blob
->data
+ ALIGN(blob
->current
- blob
->data
, alignment
);
105 struct blob
*blob
= (struct blob
*) malloc(sizeof(struct blob
));
112 blob
->out_of_memory
= false;
118 blob_overwrite_bytes(struct blob
*blob
,
123 /* Detect an attempt to overwrite data out of bounds. */
124 if (blob
->size
< offset
+ to_write
)
127 VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes
, to_write
));
129 memcpy(blob
->data
+ offset
, bytes
, to_write
);
135 blob_write_bytes(struct blob
*blob
, const void *bytes
, size_t to_write
)
137 if (! grow_to_fit(blob
, to_write
))
140 VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes
, to_write
));
142 memcpy(blob
->data
+ blob
->size
, bytes
, to_write
);
143 blob
->size
+= to_write
;
149 blob_reserve_bytes(struct blob
*blob
, size_t to_write
)
153 if (! grow_to_fit (blob
, to_write
))
156 ret
= blob
->data
+ blob
->size
;
157 blob
->size
+= to_write
;
163 blob_write_uint32(struct blob
*blob
, uint32_t value
)
165 align_blob(blob
, sizeof(value
));
167 return blob_write_bytes(blob
, &value
, sizeof(value
));
171 blob_overwrite_uint32 (struct blob
*blob
,
175 return blob_overwrite_bytes(blob
, offset
, &value
, sizeof(value
));
179 blob_write_uint64(struct blob
*blob
, uint64_t value
)
181 align_blob(blob
, sizeof(value
));
183 return blob_write_bytes(blob
, &value
, sizeof(value
));
187 blob_write_intptr(struct blob
*blob
, intptr_t value
)
189 align_blob(blob
, sizeof(value
));
191 return blob_write_bytes(blob
, &value
, sizeof(value
));
195 blob_write_string(struct blob
*blob
, const char *str
)
197 return blob_write_bytes(blob
, str
, strlen(str
) + 1);
201 blob_reader_init(struct blob_reader
*blob
, uint8_t *data
, size_t size
)
204 blob
->end
= data
+ size
;
205 blob
->current
= data
;
206 blob
->overrun
= false;
209 /* Check that an object of size \size can be read from this blob.
211 * If not, set blob->overrun to indicate that we attempted to read too far.
214 ensure_can_read(struct blob_reader
*blob
, size_t size
)
219 if (blob
->current
< blob
->end
&& blob
->end
- blob
->current
>= size
)
222 blob
->overrun
= true;
228 blob_read_bytes(struct blob_reader
*blob
, size_t size
)
232 if (! ensure_can_read (blob
, size
))
237 blob
->current
+= size
;
243 blob_copy_bytes(struct blob_reader
*blob
, uint8_t *dest
, size_t size
)
247 bytes
= blob_read_bytes(blob
, size
);
251 memcpy(dest
, bytes
, size
);
254 /* These next three read functions have identical form. If we add any beyond
255 * these first three we should probably switch to generating these with a
256 * preprocessor macro.
259 blob_read_uint32(struct blob_reader
*blob
)
262 int size
= sizeof(ret
);
264 align_blob_reader(blob
, size
);
266 if (! ensure_can_read(blob
, size
))
269 ret
= *((uint32_t*) blob
->current
);
271 blob
->current
+= size
;
277 blob_read_uint64(struct blob_reader
*blob
)
280 int size
= sizeof(ret
);
282 align_blob_reader(blob
, size
);
284 if (! ensure_can_read(blob
, size
))
287 ret
= *((uint64_t*) blob
->current
);
289 blob
->current
+= size
;
295 blob_read_intptr(struct blob_reader
*blob
)
298 int size
= sizeof(ret
);
300 align_blob_reader(blob
, size
);
302 if (! ensure_can_read(blob
, size
))
305 ret
= *((intptr_t *) blob
->current
);
307 blob
->current
+= size
;
313 blob_read_string(struct blob_reader
*blob
)
319 /* If we're already at the end, then this is an overrun. */
320 if (blob
->current
>= blob
->end
) {
321 blob
->overrun
= true;
325 /* Similarly, if there is no zero byte in the data remaining in this blob,
326 * we also consider that an overrun.
328 nul
= memchr(blob
->current
, 0, blob
->end
- blob
->current
);
331 blob
->overrun
= true;
335 size
= nul
- blob
->current
+ 1;
337 assert(ensure_can_read(blob
, size
));
339 ret
= (char *) blob
->current
;
341 blob
->current
+= size
;