Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(66)

Side by Side Diff: third_party/afl/src/alloc-inl.h

Issue 2075883002: Add American Fuzzy Lop (afl) to third_party/afl/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix nits Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/afl/src/afl-whatsup ('k') | third_party/afl/src/config.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 american fuzzy lop - error-checking, memory-zeroing alloc routines
3 ------------------------------------------------------------------
4
5 Written and maintained by Michal Zalewski <lcamtuf@google.com>
6
7 Copyright 2013, 2014, 2015 Google Inc. All rights reserved.
8
9 Licensed under the Apache License, Version 2.0 (the "License");
10 you may not use this file except in compliance with the License.
11 You may obtain a copy of the License at:
12
13 http://www.apache.org/licenses/LICENSE-2.0
14
15 This allocator is not designed to resist malicious attackers (the canaries
16 are small and predictable), but provides a robust and portable way to detect
17 use-after-free, off-by-one writes, stale pointers, and so on.
18
19 */
20
21 #ifndef _HAVE_ALLOC_INL_H
22 #define _HAVE_ALLOC_INL_H
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "config.h"
29 #include "types.h"
30 #include "debug.h"
31
32 /* User-facing macro to sprintf() to a dynamically allocated buffer. */
33
34 #define alloc_printf(_str...) ({ \
35 u8* _tmp; \
36 s32 _len = snprintf(NULL, 0, _str); \
37 if (_len < 0) FATAL("Whoa, snprintf() fails?!"); \
38 _tmp = ck_alloc(_len + 1); \
39 snprintf((char*)_tmp, _len + 1, _str); \
40 _tmp; \
41 })
42
43 /* Macro to enforce allocation limits as a last-resort defense against
44 integer overflows. */
45
46 #define ALLOC_CHECK_SIZE(_s) do { \
47 if ((_s) > MAX_ALLOC) \
48 ABORT("Bad alloc request: %u bytes", (_s)); \
49 } while (0)
50
51 /* Macro to check malloc() failures and the like. */
52
53 #define ALLOC_CHECK_RESULT(_r, _s) do { \
54 if (!(_r)) \
55 ABORT("Out of memory: can't allocate %u bytes", (_s)); \
56 } while (0)
57
58 /* Magic tokens used to mark used / freed chunks. */
59
60 #define ALLOC_MAGIC_C1 0xFF00FF00 /* Used head (dword) */
61 #define ALLOC_MAGIC_F 0xFE00FE00 /* Freed head (dword) */
62 #define ALLOC_MAGIC_C2 0xF0 /* Used tail (byte) */
63
64 /* Positions of guard tokens in relation to the user-visible pointer. */
65
66 #define ALLOC_C1(_ptr) (((u32*)(_ptr))[-2])
67 #define ALLOC_S(_ptr) (((u32*)(_ptr))[-1])
68 #define ALLOC_C2(_ptr) (((u8*)(_ptr))[ALLOC_S(_ptr)])
69
70 #define ALLOC_OFF_HEAD 8
71 #define ALLOC_OFF_TOTAL (ALLOC_OFF_HEAD + 1)
72
73 /* Allocator increments for ck_realloc_block(). */
74
75 #define ALLOC_BLK_INC 256
76
77 /* Sanity-checking macros for pointers. */
78
79 #define CHECK_PTR(_p) do { \
80 if (_p) { \
81 if (ALLOC_C1(_p) ^ ALLOC_MAGIC_C1) {\
82 if (ALLOC_C1(_p) == ALLOC_MAGIC_F) \
83 ABORT("Use after free."); \
84 else ABORT("Corrupted head alloc canary."); \
85 } \
86 if (ALLOC_C2(_p) ^ ALLOC_MAGIC_C2) \
87 ABORT("Corrupted tail alloc canary."); \
88 } \
89 } while (0)
90
91 #define CHECK_PTR_EXPR(_p) ({ \
92 typeof (_p) _tmp = (_p); \
93 CHECK_PTR(_tmp); \
94 _tmp; \
95 })
96
97
98 /* Allocate a buffer, explicitly not zeroing it. Returns NULL for zero-sized
99 requests. */
100
101 static inline void* DFL_ck_alloc_nozero(u32 size) {
102
103 void* ret;
104
105 if (!size) return NULL;
106
107 ALLOC_CHECK_SIZE(size);
108 ret = malloc(size + ALLOC_OFF_TOTAL);
109 ALLOC_CHECK_RESULT(ret, size);
110
111 ret += ALLOC_OFF_HEAD;
112
113 ALLOC_C1(ret) = ALLOC_MAGIC_C1;
114 ALLOC_S(ret) = size;
115 ALLOC_C2(ret) = ALLOC_MAGIC_C2;
116
117 return ret;
118
119 }
120
121
122 /* Allocate a buffer, returning zeroed memory. */
123
124 static inline void* DFL_ck_alloc(u32 size) {
125
126 void* mem;
127
128 if (!size) return NULL;
129 mem = DFL_ck_alloc_nozero(size);
130
131 return memset(mem, 0, size);
132
133 }
134
135
136 /* Free memory, checking for double free and corrupted heap. When DEBUG_BUILD
137 is set, the old memory will be also clobbered with 0xFF. */
138
139 static inline void DFL_ck_free(void* mem) {
140
141 if (!mem) return;
142
143 CHECK_PTR(mem);
144
145 #ifdef DEBUG_BUILD
146
147 /* Catch pointer issues sooner. */
148 memset(mem, 0xFF, ALLOC_S(mem));
149
150 #endif /* DEBUG_BUILD */
151
152 ALLOC_C1(mem) = ALLOC_MAGIC_F;
153
154 free(mem - ALLOC_OFF_HEAD);
155
156 }
157
158
159 /* Re-allocate a buffer, checking for issues and zeroing any newly-added tail.
160 With DEBUG_BUILD, the buffer is always reallocated to a new addresses and the
161 old memory is clobbered with 0xFF. */
162
163 static inline void* DFL_ck_realloc(void* orig, u32 size) {
164
165 void* ret;
166 u32 old_size = 0;
167
168 if (!size) {
169
170 DFL_ck_free(orig);
171 return NULL;
172
173 }
174
175 if (orig) {
176
177 CHECK_PTR(orig);
178
179 #ifndef DEBUG_BUILD
180 ALLOC_C1(orig) = ALLOC_MAGIC_F;
181 #endif /* !DEBUG_BUILD */
182
183 old_size = ALLOC_S(orig);
184 orig -= ALLOC_OFF_HEAD;
185
186 ALLOC_CHECK_SIZE(old_size);
187
188 }
189
190 ALLOC_CHECK_SIZE(size);
191
192 #ifndef DEBUG_BUILD
193
194 ret = realloc(orig, size + ALLOC_OFF_TOTAL);
195 ALLOC_CHECK_RESULT(ret, size);
196
197 #else
198
199 /* Catch pointer issues sooner: force relocation and make sure that the
200 original buffer is wiped. */
201
202 ret = malloc(size + ALLOC_OFF_TOTAL);
203 ALLOC_CHECK_RESULT(ret, size);
204
205 if (orig) {
206
207 memcpy(ret + ALLOC_OFF_HEAD, orig + ALLOC_OFF_HEAD, MIN(size, old_size));
208 memset(orig + ALLOC_OFF_HEAD, 0xFF, old_size);
209
210 ALLOC_C1(orig + ALLOC_OFF_HEAD) = ALLOC_MAGIC_F;
211
212 free(orig);
213
214 }
215
216 #endif /* ^!DEBUG_BUILD */
217
218 ret += ALLOC_OFF_HEAD;
219
220 ALLOC_C1(ret) = ALLOC_MAGIC_C1;
221 ALLOC_S(ret) = size;
222 ALLOC_C2(ret) = ALLOC_MAGIC_C2;
223
224 if (size > old_size)
225 memset(ret + old_size, 0, size - old_size);
226
227 return ret;
228
229 }
230
231
232 /* Re-allocate a buffer with ALLOC_BLK_INC increments (used to speed up
233 repeated small reallocs without complicating the user code). */
234
235 static inline void* DFL_ck_realloc_block(void* orig, u32 size) {
236
237 #ifndef DEBUG_BUILD
238
239 if (orig) {
240
241 CHECK_PTR(orig);
242
243 if (ALLOC_S(orig) >= size) return orig;
244
245 size += ALLOC_BLK_INC;
246
247 }
248
249 #endif /* !DEBUG_BUILD */
250
251 return DFL_ck_realloc(orig, size);
252
253 }
254
255
256 /* Create a buffer with a copy of a string. Returns NULL for NULL inputs. */
257
258 static inline u8* DFL_ck_strdup(u8* str) {
259
260 void* ret;
261 u32 size;
262
263 if (!str) return NULL;
264
265 size = strlen((char*)str) + 1;
266
267 ALLOC_CHECK_SIZE(size);
268 ret = malloc(size + ALLOC_OFF_TOTAL);
269 ALLOC_CHECK_RESULT(ret, size);
270
271 ret += ALLOC_OFF_HEAD;
272
273 ALLOC_C1(ret) = ALLOC_MAGIC_C1;
274 ALLOC_S(ret) = size;
275 ALLOC_C2(ret) = ALLOC_MAGIC_C2;
276
277 return memcpy(ret, str, size);
278
279 }
280
281
282 /* Create a buffer with a copy of a memory block. Returns NULL for zero-sized
283 or NULL inputs. */
284
285 static inline void* DFL_ck_memdup(void* mem, u32 size) {
286
287 void* ret;
288
289 if (!mem || !size) return NULL;
290
291 ALLOC_CHECK_SIZE(size);
292 ret = malloc(size + ALLOC_OFF_TOTAL);
293 ALLOC_CHECK_RESULT(ret, size);
294
295 ret += ALLOC_OFF_HEAD;
296
297 ALLOC_C1(ret) = ALLOC_MAGIC_C1;
298 ALLOC_S(ret) = size;
299 ALLOC_C2(ret) = ALLOC_MAGIC_C2;
300
301 return memcpy(ret, mem, size);
302
303 }
304
305
306 /* Create a buffer with a block of text, appending a NUL terminator at the end.
307 Returns NULL for zero-sized or NULL inputs. */
308
309 static inline u8* DFL_ck_memdup_str(u8* mem, u32 size) {
310
311 u8* ret;
312
313 if (!mem || !size) return NULL;
314
315 ALLOC_CHECK_SIZE(size);
316 ret = malloc(size + ALLOC_OFF_TOTAL + 1);
317 ALLOC_CHECK_RESULT(ret, size);
318
319 ret += ALLOC_OFF_HEAD;
320
321 ALLOC_C1(ret) = ALLOC_MAGIC_C1;
322 ALLOC_S(ret) = size;
323 ALLOC_C2(ret) = ALLOC_MAGIC_C2;
324
325 memcpy(ret, mem, size);
326 ret[size] = 0;
327
328 return ret;
329
330 }
331
332
333 #ifndef DEBUG_BUILD
334
335 /* In non-debug mode, we just do straightforward aliasing of the above functions
336 to user-visible names such as ck_alloc(). */
337
338 #define ck_alloc DFL_ck_alloc
339 #define ck_alloc_nozero DFL_ck_alloc_nozero
340 #define ck_realloc DFL_ck_realloc
341 #define ck_realloc_block DFL_ck_realloc_block
342 #define ck_strdup DFL_ck_strdup
343 #define ck_memdup DFL_ck_memdup
344 #define ck_memdup_str DFL_ck_memdup_str
345 #define ck_free DFL_ck_free
346
347 #define alloc_report()
348
349 #else
350
351 /* In debugging mode, we also track allocations to detect memory leaks, and the
352 flow goes through one more layer of indirection. */
353
354 /* Alloc tracking data structures: */
355
356 #define ALLOC_BUCKETS 4096
357
358 struct TRK_obj {
359 void *ptr;
360 char *file, *func;
361 u32 line;
362 };
363
364 #ifdef AFL_MAIN
365
366 struct TRK_obj* TRK[ALLOC_BUCKETS];
367 u32 TRK_cnt[ALLOC_BUCKETS];
368
369 # define alloc_report() TRK_report()
370
371 #else
372
373 extern struct TRK_obj* TRK[ALLOC_BUCKETS];
374 extern u32 TRK_cnt[ALLOC_BUCKETS];
375
376 # define alloc_report()
377
378 #endif /* ^AFL_MAIN */
379
380 /* Bucket-assigning function for a given pointer: */
381
382 #define TRKH(_ptr) (((((u32)(_ptr)) >> 16) ^ ((u32)(_ptr))) % ALLOC_BUCKETS)
383
384
385 /* Add a new entry to the list of allocated objects. */
386
387 static inline void TRK_alloc_buf(void* ptr, const char* file, const char* func,
388 u32 line) {
389
390 u32 i, bucket;
391
392 if (!ptr) return;
393
394 bucket = TRKH(ptr);
395
396 /* Find a free slot in the list of entries for that bucket. */
397
398 for (i = 0; i < TRK_cnt[bucket]; i++)
399
400 if (!TRK[bucket][i].ptr) {
401
402 TRK[bucket][i].ptr = ptr;
403 TRK[bucket][i].file = (char*)file;
404 TRK[bucket][i].func = (char*)func;
405 TRK[bucket][i].line = line;
406 return;
407
408 }
409
410 /* No space available - allocate more. */
411
412 TRK[bucket] = DFL_ck_realloc_block(TRK[bucket],
413 (TRK_cnt[bucket] + 1) * sizeof(struct TRK_obj));
414
415 TRK[bucket][i].ptr = ptr;
416 TRK[bucket][i].file = (char*)file;
417 TRK[bucket][i].func = (char*)func;
418 TRK[bucket][i].line = line;
419
420 TRK_cnt[bucket]++;
421
422 }
423
424
425 /* Remove entry from the list of allocated objects. */
426
427 static inline void TRK_free_buf(void* ptr, const char* file, const char* func,
428 u32 line) {
429
430 u32 i, bucket;
431
432 if (!ptr) return;
433
434 bucket = TRKH(ptr);
435
436 /* Find the element on the list... */
437
438 for (i = 0; i < TRK_cnt[bucket]; i++)
439
440 if (TRK[bucket][i].ptr == ptr) {
441
442 TRK[bucket][i].ptr = 0;
443 return;
444
445 }
446
447 WARNF("ALLOC: Attempt to free non-allocated memory in %s (%s:%u)",
448 func, file, line);
449
450 }
451
452
453 /* Do a final report on all non-deallocated objects. */
454
455 static inline void TRK_report(void) {
456
457 u32 i, bucket;
458
459 fflush(0);
460
461 for (bucket = 0; bucket < ALLOC_BUCKETS; bucket++)
462 for (i = 0; i < TRK_cnt[bucket]; i++)
463 if (TRK[bucket][i].ptr)
464 WARNF("ALLOC: Memory never freed, created in %s (%s:%u)",
465 TRK[bucket][i].func, TRK[bucket][i].file, TRK[bucket][i].line);
466
467 }
468
469
470 /* Simple wrappers for non-debugging functions: */
471
472 static inline void* TRK_ck_alloc(u32 size, const char* file, const char* func,
473 u32 line) {
474
475 void* ret = DFL_ck_alloc(size);
476 TRK_alloc_buf(ret, file, func, line);
477 return ret;
478
479 }
480
481
482 static inline void* TRK_ck_realloc(void* orig, u32 size, const char* file,
483 const char* func, u32 line) {
484
485 void* ret = DFL_ck_realloc(orig, size);
486 TRK_free_buf(orig, file, func, line);
487 TRK_alloc_buf(ret, file, func, line);
488 return ret;
489
490 }
491
492
493 static inline void* TRK_ck_realloc_block(void* orig, u32 size, const char* file,
494 const char* func, u32 line) {
495
496 void* ret = DFL_ck_realloc_block(orig, size);
497 TRK_free_buf(orig, file, func, line);
498 TRK_alloc_buf(ret, file, func, line);
499 return ret;
500
501 }
502
503
504 static inline void* TRK_ck_strdup(u8* str, const char* file, const char* func,
505 u32 line) {
506
507 void* ret = DFL_ck_strdup(str);
508 TRK_alloc_buf(ret, file, func, line);
509 return ret;
510
511 }
512
513
514 static inline void* TRK_ck_memdup(void* mem, u32 size, const char* file,
515 const char* func, u32 line) {
516
517 void* ret = DFL_ck_memdup(mem, size);
518 TRK_alloc_buf(ret, file, func, line);
519 return ret;
520
521 }
522
523
524 static inline void* TRK_ck_memdup_str(void* mem, u32 size, const char* file,
525 const char* func, u32 line) {
526
527 void* ret = DFL_ck_memdup_str(mem, size);
528 TRK_alloc_buf(ret, file, func, line);
529 return ret;
530
531 }
532
533
534 static inline void TRK_ck_free(void* ptr, const char* file,
535 const char* func, u32 line) {
536
537 TRK_free_buf(ptr, file, func, line);
538 DFL_ck_free(ptr);
539
540 }
541
542 /* Aliasing user-facing names to tracking functions: */
543
544 #define ck_alloc(_p1) \
545 TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
546
547 #define ck_alloc_nozero(_p1) \
548 TRK_ck_alloc(_p1, __FILE__, __FUNCTION__, __LINE__)
549
550 #define ck_realloc(_p1, _p2) \
551 TRK_ck_realloc(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
552
553 #define ck_realloc_block(_p1, _p2) \
554 TRK_ck_realloc_block(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
555
556 #define ck_strdup(_p1) \
557 TRK_ck_strdup(_p1, __FILE__, __FUNCTION__, __LINE__)
558
559 #define ck_memdup(_p1, _p2) \
560 TRK_ck_memdup(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
561
562 #define ck_memdup_str(_p1, _p2) \
563 TRK_ck_memdup_str(_p1, _p2, __FILE__, __FUNCTION__, __LINE__)
564
565 #define ck_free(_p1) \
566 TRK_ck_free(_p1, __FILE__, __FUNCTION__, __LINE__)
567
568 #endif /* ^!DEBUG_BUILD */
569
570 #endif /* ! _HAVE_ALLOC_INL_H */
OLDNEW
« no previous file with comments | « third_party/afl/src/afl-whatsup ('k') | third_party/afl/src/config.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698