Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/util/blob.c
4547 views
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 "blob.h"
27
#include "u_math.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 = align64(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 + align64(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
void
129
blob_finish_get_buffer(struct blob *blob, void **buffer, size_t *size)
130
{
131
*buffer = blob->data;
132
*size = blob->size;
133
blob->data = NULL;
134
135
/* Trim the buffer. */
136
*buffer = realloc(*buffer, *size);
137
}
138
139
bool
140
blob_overwrite_bytes(struct blob *blob,
141
size_t offset,
142
const void *bytes,
143
size_t to_write)
144
{
145
/* Detect an attempt to overwrite data out of bounds. */
146
if (offset + to_write < offset || blob->size < offset + to_write)
147
return false;
148
149
VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write));
150
151
if (blob->data)
152
memcpy(blob->data + offset, bytes, to_write);
153
154
return true;
155
}
156
157
bool
158
blob_write_bytes(struct blob *blob, const void *bytes, size_t to_write)
159
{
160
if (! grow_to_fit(blob, to_write))
161
return false;
162
163
VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write));
164
165
if (blob->data && to_write > 0)
166
memcpy(blob->data + blob->size, bytes, to_write);
167
blob->size += to_write;
168
169
return true;
170
}
171
172
intptr_t
173
blob_reserve_bytes(struct blob *blob, size_t to_write)
174
{
175
intptr_t ret;
176
177
if (! grow_to_fit (blob, to_write))
178
return -1;
179
180
ret = blob->size;
181
blob->size += to_write;
182
183
return ret;
184
}
185
186
intptr_t
187
blob_reserve_uint32(struct blob *blob)
188
{
189
align_blob(blob, sizeof(uint32_t));
190
return blob_reserve_bytes(blob, sizeof(uint32_t));
191
}
192
193
intptr_t
194
blob_reserve_intptr(struct blob *blob)
195
{
196
align_blob(blob, sizeof(intptr_t));
197
return blob_reserve_bytes(blob, sizeof(intptr_t));
198
}
199
200
#define BLOB_WRITE_TYPE(name, type) \
201
bool \
202
name(struct blob *blob, type value) \
203
{ \
204
align_blob(blob, sizeof(value)); \
205
return blob_write_bytes(blob, &value, sizeof(value)); \
206
}
207
208
BLOB_WRITE_TYPE(blob_write_uint8, uint8_t)
209
BLOB_WRITE_TYPE(blob_write_uint16, uint16_t)
210
BLOB_WRITE_TYPE(blob_write_uint32, uint32_t)
211
BLOB_WRITE_TYPE(blob_write_uint64, uint64_t)
212
BLOB_WRITE_TYPE(blob_write_intptr, intptr_t)
213
214
#define ASSERT_ALIGNED(_offset, _align) \
215
assert(align64((_offset), (_align)) == (_offset))
216
217
bool
218
blob_overwrite_uint8 (struct blob *blob,
219
size_t offset,
220
uint8_t value)
221
{
222
ASSERT_ALIGNED(offset, sizeof(value));
223
return blob_overwrite_bytes(blob, offset, &value, sizeof(value));
224
}
225
226
bool
227
blob_overwrite_uint32 (struct blob *blob,
228
size_t offset,
229
uint32_t value)
230
{
231
ASSERT_ALIGNED(offset, sizeof(value));
232
return blob_overwrite_bytes(blob, offset, &value, sizeof(value));
233
}
234
235
bool
236
blob_overwrite_intptr (struct blob *blob,
237
size_t offset,
238
intptr_t value)
239
{
240
ASSERT_ALIGNED(offset, sizeof(value));
241
return blob_overwrite_bytes(blob, offset, &value, sizeof(value));
242
}
243
244
bool
245
blob_write_string(struct blob *blob, const char *str)
246
{
247
return blob_write_bytes(blob, str, strlen(str) + 1);
248
}
249
250
void
251
blob_reader_init(struct blob_reader *blob, const void *data, size_t size)
252
{
253
blob->data = data;
254
blob->end = blob->data + size;
255
blob->current = data;
256
blob->overrun = false;
257
}
258
259
/* Check that an object of size \size can be read from this blob.
260
*
261
* If not, set blob->overrun to indicate that we attempted to read too far.
262
*/
263
static bool
264
ensure_can_read(struct blob_reader *blob, size_t size)
265
{
266
if (blob->overrun)
267
return false;
268
269
if (blob->current <= blob->end && blob->end - blob->current >= size)
270
return true;
271
272
blob->overrun = true;
273
274
return false;
275
}
276
277
const void *
278
blob_read_bytes(struct blob_reader *blob, size_t size)
279
{
280
const void *ret;
281
282
if (! ensure_can_read (blob, size))
283
return NULL;
284
285
ret = blob->current;
286
287
blob->current += size;
288
289
return ret;
290
}
291
292
void
293
blob_copy_bytes(struct blob_reader *blob, void *dest, size_t size)
294
{
295
const void *bytes;
296
297
bytes = blob_read_bytes(blob, size);
298
if (bytes == NULL || size == 0)
299
return;
300
301
memcpy(dest, bytes, size);
302
}
303
304
void
305
blob_skip_bytes(struct blob_reader *blob, size_t size)
306
{
307
if (ensure_can_read (blob, size))
308
blob->current += size;
309
}
310
311
/* These next three read functions have identical form. If we add any beyond
312
* these first three we should probably switch to generating these with a
313
* preprocessor macro.
314
*/
315
316
#define BLOB_READ_TYPE(name, type) \
317
type \
318
name(struct blob_reader *blob) \
319
{ \
320
type ret; \
321
int size = sizeof(ret); \
322
align_blob_reader(blob, size); \
323
if (! ensure_can_read(blob, size)) \
324
return 0; \
325
ret = *((type*) blob->current); \
326
blob->current += size; \
327
return ret; \
328
}
329
330
BLOB_READ_TYPE(blob_read_uint8, uint8_t)
331
BLOB_READ_TYPE(blob_read_uint16, uint16_t)
332
BLOB_READ_TYPE(blob_read_uint32, uint32_t)
333
BLOB_READ_TYPE(blob_read_uint64, uint64_t)
334
BLOB_READ_TYPE(blob_read_intptr, intptr_t)
335
336
char *
337
blob_read_string(struct blob_reader *blob)
338
{
339
int size;
340
char *ret;
341
uint8_t *nul;
342
343
/* If we're already at the end, then this is an overrun. */
344
if (blob->current >= blob->end) {
345
blob->overrun = true;
346
return NULL;
347
}
348
349
/* Similarly, if there is no zero byte in the data remaining in this blob,
350
* we also consider that an overrun.
351
*/
352
nul = memchr(blob->current, 0, blob->end - blob->current);
353
354
if (nul == NULL) {
355
blob->overrun = true;
356
return NULL;
357
}
358
359
size = nul - blob->current + 1;
360
361
assert(ensure_can_read(blob, size));
362
363
ret = (char *) blob->current;
364
365
blob->current += size;
366
367
return ret;
368
}
369
370