1#include <console/crash.h>
2#include <dbg.h>
3#include <global.h>
4#include <kassert.h>
5#include <math/align.h>
6#include <mem/asan.h>
7#include <mem/hhdm.h>
8#include <mem/page.h>
9#include <mem/pmm.h>
10#include <mem/vmm.h>
11#include <ndjson.h>
12#include <stack_depot.h>
13#include <stdint.h>
14#include <string.h>
15#include <sync/spinlock.h>
16
17#include "mem/slab/internal.h"
18
19#define kasan_panic(what, addr, size, is_write) \
20 do { \
21 char _kasan_msg[CRASH_MSG_MAX]; \
22 snprintf(_kasan_msg, sizeof(_kasan_msg), \
23 "KASAN: %s at %p (size=%zu, %s)", (what), (addr), \
24 (size_t) (size), (is_write) ? "store" : "load"); \
25 crash_full(&(struct crash_context){ \
26 .source = CRASH_SOURCE_KASAN, \
27 .formats = CRASH_FMT_DEFAULT, \
28 .file = __FILE__, \
29 .line = __LINE__, \
30 .func = __func__, \
31 .msg = _kasan_msg, \
32 }); \
33 } while (0)
34
35#ifdef DEBUG_ASAN
36LOG_SITE_DECLARE_PRINT(asan);
37LOG_HANDLE_DECLARE_PRINT(asan);
38
39/* If we widen this, ASAN_SHADOW_OFFSET must be recomputed, because right now
40 * it maps exactly this window into the shadow region */
41#define ASAN_COVERED_START SLAB_HEAP_START
42#define ASAN_COVERED_END SLAB_HEAP_END
43
44static bool asan_ready = false;
45
46/* Two pages that everything aliases to for pages that are fully OK/not OK to
47 * read/modify */
48static paddr_t asan_zero_shadow_phys; /* never had a chunk: reads accessible */
49static paddr_t asan_freed_shadow_phys; /* had one, gave it back: reads freed */
50
51static inline bool asan_addr_covered(uintptr_t a, size_t size) {
52 return a >= ASAN_COVERED_START && (a + size) <= ASAN_COVERED_END;
53}
54
55static inline uint8_t *asan_shadow_for_internal(const void *addr) {
56 return (uint8_t *) ASAN_SHADOW_ADDR(addr);
57}
58
59/* Number of shadow bytes covering [addr, addr + size) */
60static inline size_t asan_shadow_span(const void *addr, size_t size) {
61 const uint8_t *end = (const uint8_t *) addr + size - 1;
62 return (size_t) (asan_shadow_for_internal(end) -
63 asan_shadow_for_internal(addr)) +
64 1;
65}
66
67static void asan_mark_valid(void *addr, size_t size) {
68 kassert(IS_ALIGNED((uintptr_t) addr, ASAN_GRANULE));
69
70 uint8_t *shadow = asan_shadow_for_internal(addr);
71 size_t full = size >> ASAN_SHADOW_SCALE;
72 size_t tail = size & (ASAN_GRANULE - 1);
73
74 memset(shadow, 0, full);
75 if (tail)
76 shadow[full] = (uint8_t) tail;
77}
78
79static void asan_mark_poisoned(void *addr, size_t size, uint8_t value) {
80 kassert(IS_ALIGNED((uintptr_t) addr, ASAN_GRANULE));
81
82 memset(asan_shadow_for_internal(addr), value, asan_shadow_span(addr, size));
83}
84
85void asan_alloc(void *addr, size_t requested, size_t slot) {
86 ASAN_ABORT_IF_NOT_READY();
87
88 if (!slot || !asan_addr_covered((uintptr_t) addr, slot))
89 return;
90
91 kassert(requested && requested <= slot);
92
93 asan_mark_valid(addr, requested);
94
95 size_t redzone = ALIGN_UP(requested, ASAN_GRANULE);
96 if (redzone < slot)
97 asan_mark_poisoned((uint8_t *) addr + redzone, slot - redzone,
98 ASAN_POISON_HEAP_REDZONE);
99}
100
101void asan_free(void *addr, size_t slot) {
102 ASAN_ABORT_IF_NOT_READY();
103
104 if (!slot || !asan_addr_covered((uintptr_t) addr, slot))
105 return;
106
107 asan_mark_poisoned(addr, slot, ASAN_POISON_HEAP_FREED);
108}
109
110void asan_poison(void *addr, size_t size) {
111 ASAN_ABORT_IF_NOT_READY();
112
113 if (!size || !asan_addr_covered((uintptr_t) addr, size))
114 return;
115
116 asan_mark_poisoned(addr, size, ASAN_POISON_VALUE);
117}
118
119void asan_unpoison(void *addr, size_t size) {
120 ASAN_ABORT_IF_NOT_READY();
121
122 if (!size || !asan_addr_covered((uintptr_t) addr, size))
123 return;
124
125 asan_mark_valid(addr, size);
126}
127
128static inline bool asan_shadow_is_shared(vaddr_t shadow_page) {
129 paddr_t p = vmm_get_phys(shadow_page);
130 return p == asan_zero_shadow_phys || p == asan_freed_shadow_phys;
131}
132
133static bool asan_page_is_uniform(const void *addr, uint8_t value) {
134 const uint64_t *p = addr;
135 uint64_t want = value * 0x0101010101010101ULL;
136
137 for (size_t i = 0; i < PAGE_SIZE / sizeof(uint64_t); i++) {
138 if (p[i] != want)
139 return false;
140 }
141
142 return true;
143}
144
145static inline vaddr_t asan_shadow_page_first(vaddr_t base) {
146 return ALIGN_DOWN(ASAN_SHADOW_ADDR(base), PAGE_SIZE);
147}
148
149static inline vaddr_t asan_shadow_page_limit(vaddr_t base, size_t len) {
150 return ALIGN_UP(ASAN_SHADOW_ADDR(base + len - 1) + 1, PAGE_SIZE);
151}
152
153enum errno asan_shadow_install(vaddr_t base, size_t len) {
154 if (!asan_ready)
155 return ERR_OK;
156
157 if (!len || !asan_addr_covered(base, len))
158 return ERR_OK;
159
160 vaddr_t limit = asan_shadow_page_limit(base, len);
161
162 for (vaddr_t v = asan_shadow_page_first(base); v < limit; v += PAGE_SIZE) {
163 if (!asan_shadow_is_shared(v))
164 continue;
165
166 /* Per page rather than once up front, so a range of any length works:
167 * the walk is cheap and only happens for a page we are about to back */
168 enum errno err =
169 vmm_unshare_path(v, VMM_MAP_PAGE_SIZE_4KB, VMM_FLAG_NONE);
170 if (err < 0)
171 return err;
172
173 paddr_t phys = pmm_alloc_page();
174 if (!phys)
175 return ERR_NO_MEM;
176
177 err =
178 vmm_map_page_internal(v, phys, PAGE_PRESENT | PAGE_WRITE | PAGE_XD,
179 VMM_FLAG_MODIFY_LEAF, VMM_MAP_PAGE_SIZE_4KB);
180 if (err < 0) {
181 pmm_free_page(phys);
182 return err;
183 }
184
185 memset((void *) v, ASAN_POISON_VALUE, PAGE_SIZE);
186 }
187
188 return ERR_OK;
189}
190
191void asan_shadow_release(vaddr_t base, size_t len) {
192 if (!asan_ready)
193 return;
194
195 if (!len || !asan_addr_covered(base, len))
196 return;
197
198 vaddr_t limit = asan_shadow_page_limit(base, len);
199
200 for (vaddr_t v = asan_shadow_page_first(base); v < limit; v += PAGE_SIZE) {
201 if (asan_shadow_is_shared(v))
202 continue;
203
204 if (!asan_page_is_uniform((void *) v, ASAN_POISON_HEAP_FREED))
205 continue;
206
207 paddr_t phys = vmm_get_phys(v);
208
209 if (vmm_map_page_internal(v, asan_freed_shadow_phys,
210 PAGE_PRESENT | PAGE_XD, VMM_FLAG_MODIFY_LEAF,
211 VMM_MAP_PAGE_SIZE_4KB) < 0)
212 continue;
213
214 pmm_free_page(phys);
215 }
216}
217
218static void asan_map_early_shadow(void) {
219 vaddr_t start = ASAN_SHADOW_ADDR(ASAN_COVERED_START);
220 vaddr_t end = ASAN_SHADOW_ADDR(ASAN_COVERED_END);
221
222 asan_zero_shadow_phys = pmm_alloc_page(ALLOC_FLAGS_ZERO);
223 if (!asan_zero_shadow_phys)
224 kasan_panic("could not allocate the shared shadow page", NULL, 0,
225 false);
226
227 asan_freed_shadow_phys = pmm_alloc_page();
228 if (!asan_freed_shadow_phys)
229 kasan_panic("could not allocate the shared freed shadow page", NULL, 0,
230 false);
231
232 memset(hhdm_paddr_to_ptr(asan_freed_shadow_phys), ASAN_POISON_HEAP_FREED,
233 PAGE_SIZE);
234
235 /* Deliberately RO and aliased */
236 enum errno err = vmm_map_aliased(start, end - start, asan_zero_shadow_phys,
237 PAGE_PRESENT | PAGE_XD, VMM_FLAG_NONE);
238 if (err < 0)
239 kasan_panic("could not map the shared shadow window",
240 (const void *) start, end - start, false);
241
242 asan_info("shared shadow: [%lx, %lx), %zu GiB of window on one zero page "
243 "at %lx\n",
244 start, end, (size_t) ((end - start) / GB(1)),
245 asan_zero_shadow_phys);
246}
247
248void asan_init(void) {
249 asan_info("bringing ASAN up...");
250
251 asan_map_early_shadow();
252
253 asan_ready = true;
254}
255
256NDJSON_DECLARE(asan_fault, NDJSON_SECTION_ASAN, NDJSON_KIND_FAULT, 1,
257 NDJSON_STR(what), NDJSON_HEX(addr), NDJSON_U64(size),
258 NDJSON_STR(access));
259
260NDJSON_DECLARE(asan_frame, NDJSON_SECTION_ASAN, NDJSON_KIND_FRAME, 1,
261 NDJSON_U64(idx), NDJSON_HEX(addr), NDJSON_STR(sym),
262 NDJSON_U64(off));
263
264static void asan_report_shadow(const void *addr) {
265 const uint8_t *sh = asan_shadow_for_internal(addr);
266
267 printf("[ASAN] shadow near %p, one byte per %u bytes, fault at column 0:\n",
268 addr, (unsigned) ASAN_GRANULE);
269 for (int row = -1; row <= 1; row++) {
270 printf("[ASAN] %+6d ", row * 16 * (int) ASAN_GRANULE);
271 for (int i = 0; i < 16; i++)
272 printf("%02x ", sh[row * 16 + i]);
273 printf("\n");
274 }
275}
276
277/* stack_depot_print is bare addresses, so we debug_symbolize */
278static void asan_report_stack(stack_handle_t h) {
279 struct stack_depot_record *rec = stack_depot_get_record(h);
280
281 if (!rec) {
282 printf("[ASAN] <trace no longer in the depot>\n");
283 return;
284 }
285
286 for (size_t i = 0; i < rec->num_entries; i++) {
287 uint64_t off = 0;
288 const char *sym = debug_symbolize(rec->entries[i], &off);
289
290 if (sym)
291 printf("[ASAN] #%-2lu %p %s+0x%lx\n", (unsigned long) i,
292 (void *) rec->entries[i], sym, (unsigned long) off);
293 else
294 printf("[ASAN] #%-2lu %p\n", (unsigned long) i,
295 (void *) rec->entries[i]);
296
297 ndjson_emit(asan_frame, .idx = i, .addr = rec->entries[i], .sym = sym,
298 .off = off);
299 }
300}
301
302/* Slabs keep a stack depot handle per object when DEBUG_SLAB_DEEP, so
303 * we must tread carefully when retrieving the backtrace, lest we
304 * dereference an unmapped page or cause other problems */
305static void asan_report_owner(const void *addr) {
306#ifdef DEBUG_SLAB_DEEP
307 static bool reporting;
308
309 if (reporting || !slab_ptr_in_slab((void *) addr))
310 return;
311 reporting = true;
312
313 if (slab_order_map_get((vaddr_t) addr) == SLAB_POW2_ORDER_EMPTY) {
314 printf("[ASAN] %p is in the slab heap but no chunk is mapped there\n",
315 addr);
316 goto out;
317 }
318
319 struct slab *s = slab_for_ptr((void *) addr);
320 struct slab_cache *cache = s->parent_cache;
321
322 /* Metadata may be what went wrong, so sanity check before trusting it */
323 if ((uintptr_t) cache < SLAB_HEAP_START || !cache->obj_stride ||
324 !cache->objs_per_slab || s->mem < (vaddr_t) s ||
325 (vaddr_t) addr < s->mem) {
326 printf("[ASAN] slab metadata at %p is not usable (cache=%p)\n",
327 (void *) s, (void *) cache);
328 goto out;
329 }
330
331 size_t idx = slab_allocation_index(s, (void *) addr);
332 if (idx >= cache->objs_per_slab) {
333 printf("[ASAN] object index %lu out of range for this slab\n",
334 (unsigned long) idx);
335 goto out;
336 }
337
338 stack_handle_t h = s->traces[idx];
339 if (!h) {
340 printf("[ASAN] object %lu of slab %p has no recorded allocation\n",
341 (unsigned long) idx, (void *) s);
342 goto out;
343 }
344
345 printf("[ASAN] object %lu of slab %p was last allocated at:\n",
346 (unsigned long) idx, (void *) s);
347 asan_report_stack(h);
348
349out:
350 reporting = false;
351#else
352 (void) addr;
353#endif
354}
355
356static void __asan_report_and_panic(const char *what, const void *addr,
357 size_t size, bool is_write) {
358 printf("[ASAN] %s at %p size=%zu %s\n", what, addr, size,
359 is_write ? "store" : "load");
360
361 ndjson_emit(asan_fault, .what = what, .addr = (uint64_t) (uintptr_t) addr,
362 .size = size, .access = is_write ? "store" : "load");
363 asan_report_shadow(addr);
364 asan_report_owner(addr);
365
366 char msg[CRASH_MSG_MAX];
367 snprintf(msg, sizeof(msg), "KASAN: %s at %p (size=%zu, %s)",
368 what ? what : "<fault>", addr, size, is_write ? "store" : "load");
369 crash_full(&(struct crash_context){
370 .source = CRASH_SOURCE_KASAN,
371 .formats = CRASH_FMT_DEFAULT,
372 .file = __FILE__,
373 .line = __LINE__,
374 .func = __func__,
375 .msg = msg,
376 });
377}
378
379static const char *asan_poison_reason(uint8_t shadow) {
380 switch (shadow) {
381 case ASAN_POISON_HEAP_FREED: return "use-after-free";
382 case ASAN_POISON_HEAP_REDZONE: return "heap redzone (out of bounds)";
383 case ASAN_POISON_VALUE: return "poisoned (unallocated)";
384 default:
385 return asan_shadow_is_poison(shadow)
386 ? "poisoned"
387 : "heap overflow (partial granule)";
388 }
389}
390
391static inline void asan_check_access_core(const void *addr, size_t size,
392 bool is_write) {
393 ASAN_ABORT_IF_NOT_READY();
394
395 if (size == 0)
396 return;
397
398 if (!asan_addr_covered((uintptr_t) addr, size))
399 return;
400
401 uintptr_t start = (uintptr_t) addr;
402 uintptr_t last = start + (size - 1);
403
404 for (uintptr_t g = start & ~(ASAN_GRANULE - 1); g <= last;
405 g += ASAN_GRANULE) {
406 uint8_t s = *asan_shadow_for_internal((const void *) g);
407 if (s == 0)
408 continue;
409
410 /* Bytes of this granule the access actually touches: [lo, hi) */
411 uintptr_t hi =
412 (last - g < ASAN_GRANULE - 1) ? (last - g) + 1 : ASAN_GRANULE;
413
414 /* A partial granule keeps its first `s` bytes accessible */
415 if (!asan_shadow_is_poison(s) && hi <= s)
416 continue;
417
418 __asan_report_and_panic(asan_poison_reason(s), addr, size, is_write);
419 return;
420 }
421}
422
423void __asan_load1(const void *addr) {
424 asan_check_access_core(addr, 1, false);
425}
426void __asan_load2(const void *addr) {
427 asan_check_access_core(addr, 2, false);
428}
429void __asan_load4(const void *addr) {
430 asan_check_access_core(addr, 4, false);
431}
432void __asan_load8(const void *addr) {
433 asan_check_access_core(addr, 8, false);
434}
435void __asan_load16(const void *addr) {
436 asan_check_access_core(addr, 16, false);
437} /* some compilers */
438
439void __asan_store1(const void *addr) {
440 asan_check_access_core(addr, 1, true);
441}
442void __asan_store2(const void *addr) {
443 asan_check_access_core(addr, 2, true);
444}
445void __asan_store4(const void *addr) {
446 asan_check_access_core(addr, 4, true);
447}
448void __asan_store8(const void *addr) {
449 asan_check_access_core(addr, 8, true);
450}
451void __asan_store16(const void *addr) {
452 asan_check_access_core(addr, 16, true);
453}
454
455/* Generic wrappers the compiler sometimes uses */
456void __asan_loadN(const void *addr, size_t size) {
457 asan_check_access_core(addr, size, false);
458}
459void __asan_storeN(const void *addr, size_t size) {
460 asan_check_access_core(addr, size, true);
461}
462
463/* The compiler's spelling of the same two operations */
464void __asan_poison_memory_region(void *addr, size_t size) {
465 asan_poison(addr, size);
466}
467
468void __asan_unpoison_memory_region(void *addr, size_t size) {
469 asan_unpoison(addr, size);
470}
471
472struct __asan_global {
473 void *addr;
474 size_t size;
475 const char *name;
476 /* some targets include more fields; we ignore them */
477};
478
479void __asan_register_globals(struct __asan_global *globals, size_t n) {
480 ASAN_ABORT_IF_NOT_READY();
481 const size_t redzone = 16;
482 for (size_t i = 0; i < n; i++) {
483 void *addr = globals[i].addr;
484 size_t size = globals[i].size;
485 if (!addr || size == 0)
486 continue;
487
488 /* poison left redzone (if address is valid) */
489 if ((uintptr_t) addr >= redzone) /* simple check */
490 __asan_poison_memory_region((uint8_t *) addr - redzone, redzone);
491 __asan_unpoison_memory_region(addr, size);
492 __asan_poison_memory_region((uint8_t *) addr + size, redzone);
493 }
494}
495
496void __asan_unregister_globals(void *globals, size_t n) {
497 (void) globals;
498 (void) n;
499}
500
501#define ASAN_MAX_STACK_RECORDS 1024
502struct stack_record {
503 void *addr;
504 size_t size;
505};
506
507static struct stack_record stack_records[ASAN_MAX_STACK_RECORDS];
508static size_t stack_records_count = 0;
509
510void __asan_stack_malloc(void *addr, size_t size) {
511 ASAN_ABORT_IF_NOT_READY();
512 if (!addr || size == 0)
513 return;
514 const size_t rz = 16;
515 __asan_poison_memory_region((uint8_t *) addr - rz, size + rz * 2);
516 __asan_unpoison_memory_region(addr, size);
517
518 if (stack_records_count < ASAN_MAX_STACK_RECORDS) {
519 stack_records[stack_records_count].addr = addr;
520 stack_records[stack_records_count].size = size;
521 stack_records_count++;
522 }
523}
524
525void __asan_stack_free(void *addr) {
526 ASAN_ABORT_IF_NOT_READY();
527 for (size_t i = 0; i < stack_records_count; i++) {
528 if (stack_records[i].addr == addr) {
529 size_t size = stack_records[i].size;
530 const size_t rz = 16;
531 __asan_poison_memory_region((uint8_t *) addr - rz, size + rz * 2);
532 /* shift tail down */
533 stack_records[i] = stack_records[stack_records_count - 1];
534 stack_records_count--;
535 return;
536 }
537 }
538}
539
540void __asan_report_load1(void *addr) {
541 __asan_report_and_panic("ASAN: load1", addr, 1, false);
542}
543void __asan_report_load2(void *addr) {
544 __asan_report_and_panic("ASAN: load2", addr, 2, false);
545}
546void __asan_report_load4(void *addr) {
547 __asan_report_and_panic("ASAN: load4", addr, 4, false);
548}
549void __asan_report_load8(void *addr) {
550 __asan_report_and_panic("ASAN: load8", addr, 8, false);
551}
552void __asan_report_load16(void *addr) {
553 __asan_report_and_panic("ASAN: invalid 16-byte load", addr, 16, false);
554}
555
556void __asan_report_load32(void *addr) {
557 __asan_report_and_panic("ASAN: invalid 32-byte load", addr, 32, false);
558}
559
560void __asan_report_load64(void *addr) {
561 __asan_report_and_panic("ASAN: invalid 64-byte load", addr, 64, false);
562}
563
564void __asan_report_load_n(void *addr, size_t size) {
565 __asan_report_and_panic("ASAN: invalid variable-size load", addr, size,
566 false);
567}
568
569void __asan_report_store1(void *addr) {
570 __asan_report_and_panic("ASAN: store1", addr, 1, true);
571}
572void __asan_report_store2(void *addr) {
573 __asan_report_and_panic("ASAN: store2", addr, 2, true);
574}
575void __asan_report_store4(void *addr) {
576 __asan_report_and_panic("ASAN: store4", addr, 4, true);
577}
578void __asan_report_store8(void *addr) {
579 __asan_report_and_panic("ASAN: store8", addr, 8, true);
580}
581void __asan_report_store16(void *addr) {
582 __asan_report_and_panic("ASAN: invalid 16-byte store", addr, 16, true);
583}
584
585void __asan_report_store32(void *addr) {
586 __asan_report_and_panic("ASAN: invalid 32-byte store", addr, 32, true);
587}
588
589void __asan_report_store64(void *addr) {
590 __asan_report_and_panic("ASAN: invalid 64-byte store", addr, 64, true);
591}
592
593void __asan_report_store_n(void *addr, size_t size) {
594 __asan_report_and_panic("ASAN: invalid variable-size store", addr, size,
595 true);
596}
597
598int __asan_option_detect_stack_use_after_return = 0;
599
600void *__asan_stack_malloc_0(size_t size) {
601 (void) size;
602 return NULL;
603}
604void *__asan_stack_malloc_1(size_t size) {
605 (void) size;
606 return NULL;
607}
608void *__asan_stack_malloc_2(size_t size) {
609 (void) size;
610 return NULL;
611}
612void *__asan_stack_malloc_3(size_t size) {
613 (void) size;
614 return NULL;
615}
616void *__asan_stack_malloc_4(size_t size) {
617 (void) size;
618 return NULL;
619}
620void *__asan_stack_malloc_5(size_t size) {
621 (void) size;
622 return NULL;
623}
624void *__asan_stack_malloc_6(size_t size) {
625 (void) size;
626 return NULL;
627}
628void *__asan_stack_malloc_7(size_t size) {
629 (void) size;
630 return NULL;
631}
632void *__asan_stack_malloc_8(size_t size) {
633 (void) size;
634 return NULL;
635}
636void *__asan_stack_malloc_9(size_t size) {
637 (void) size;
638 return NULL;
639}
640
641void __asan_stack_free_0(void *p, size_t size) {
642 (void) p;
643 (void) size;
644}
645void __asan_stack_free_1(void *p, size_t size) {
646 (void) p;
647 (void) size;
648}
649void __asan_stack_free_2(void *p, size_t size) {
650 (void) p;
651 (void) size;
652}
653void __asan_stack_free_3(void *p, size_t size) {
654 (void) p;
655 (void) size;
656}
657void __asan_stack_free_4(void *p, size_t size) {
658 (void) p;
659 (void) size;
660}
661void __asan_stack_free_5(void *p, size_t size) {
662 (void) p;
663 (void) size;
664}
665void __asan_stack_free_6(void *p, size_t size) {
666 (void) p;
667 (void) size;
668}
669void __asan_stack_free_7(void *p, size_t size) {
670 (void) p;
671 (void) size;
672}
673void __asan_stack_free_8(void *p, size_t size) {
674 (void) p;
675 (void) size;
676}
677void __asan_stack_free_9(void *p, size_t size) {
678 (void) p;
679 (void) size;
680}
681
682void *__asan_malloc(size_t size) {
683 /* Not relevant for kernel: just panic if somehow called */
684 __asan_report_and_panic("asan_malloc called", NULL, size, true);
685 return NULL;
686}
687
688void __asan_free(void *p) {
689 __asan_report_and_panic("asan_free called", p, 0, true);
690}
691
692void __asan_malloc_hook(void *ptr, size_t size) {
693 (void) ptr;
694 (void) size;
695}
696void __asan_free_hook(void *ptr) {
697 (void) ptr;
698}
699
700void __asan_init(void) {
701 asan_info("__asan_init runtime stub called");
702}
703
704void __asan_before_dynamic_init(const char *module_name) {
705 (void) module_name;
706}
707void __asan_after_dynamic_init(void) {}
708
709/* Compiler sometimes emits these for non-instrumented copies. */
710void *__asan_memcpy(void *dst, const void *src, size_t n) {
711 return memcpy(dst, src, n);
712}
713void *__asan_memmove(void *dst, const void *src, size_t n) {
714 return memmove(dst, src, n);
715}
716void *__asan_memset(void *s, int c, size_t n) {
717 return memset(s, c, n);
718}
719
720/* Some compilers also expect these “weak” entrypoints */
721void __asan_handle_no_return(void) {}
722void __asan_after_load(void) {}
723void __asan_after_store(void) {}
724void __asan_before_memory_access(void) {}
725void __asan_after_memory_access(void) {}
726
727/* Optional runtime interface for global poisoning/unpoisoning */
728void __asan_set_shadow_00_to_0x00(void) {}
729void __asan_set_shadow_f8_to_0x00(void) {}
730
731void __asan_alloca_poison(void *addr, size_t size) {
732 ASAN_ABORT_IF_NOT_READY();
733 if (!addr || size == 0)
734 return;
735 __asan_poison_memory_region(addr, size);
736}
737
738void __asan_allocas_unpoison(void *addr, size_t size) {
739 ASAN_ABORT_IF_NOT_READY();
740 if (!addr || size == 0)
741 return;
742 __asan_unpoison_memory_region(addr, size);
743}
744
745__attribute__((weak)) void __asan_alloca_poison_0(void *addr, size_t size) {
746 __asan_alloca_poison(addr, size);
747}
748
749__attribute__((weak)) void __asan_allocas_unpoison_0(void *addr, size_t size) {
750 __asan_allocas_unpoison(addr, size);
751}
752
753#define ASAN_ALIAS(name, target) __attribute__((alias(#target))) void name
754
755/* Outline callbacks (forced via -asan-instrumentation-with-call-threshold=0).
756 */
757ASAN_ALIAS(__asan_load1_noabort, __asan_load1)(const void *addr);
758ASAN_ALIAS(__asan_load2_noabort, __asan_load2)(const void *addr);
759ASAN_ALIAS(__asan_load4_noabort, __asan_load4)(const void *addr);
760ASAN_ALIAS(__asan_load8_noabort, __asan_load8)(const void *addr);
761ASAN_ALIAS(__asan_load16_noabort, __asan_load16)(const void *addr);
762ASAN_ALIAS(__asan_store1_noabort, __asan_store1)(const void *addr);
763ASAN_ALIAS(__asan_store2_noabort, __asan_store2)(const void *addr);
764ASAN_ALIAS(__asan_store4_noabort, __asan_store4)(const void *addr);
765ASAN_ALIAS(__asan_store8_noabort, __asan_store8)(const void *addr);
766ASAN_ALIAS(__asan_store16_noabort, __asan_store16)(const void *addr);
767ASAN_ALIAS(__asan_loadN_noabort, __asan_loadN)(const void *addr, size_t size);
768ASAN_ALIAS(__asan_storeN_noabort, __asan_storeN)(const void *addr, size_t size);
769
770ASAN_ALIAS(__asan_report_load1_noabort, __asan_report_load1)(void *addr);
771ASAN_ALIAS(__asan_report_load2_noabort, __asan_report_load2)(void *addr);
772ASAN_ALIAS(__asan_report_load4_noabort, __asan_report_load4)(void *addr);
773ASAN_ALIAS(__asan_report_load8_noabort, __asan_report_load8)(void *addr);
774ASAN_ALIAS(__asan_report_load16_noabort, __asan_report_load16)(void *addr);
775ASAN_ALIAS(__asan_report_store1_noabort, __asan_report_store1)(void *addr);
776ASAN_ALIAS(__asan_report_store2_noabort, __asan_report_store2)(void *addr);
777ASAN_ALIAS(__asan_report_store4_noabort, __asan_report_store4)(void *addr);
778ASAN_ALIAS(__asan_report_store8_noabort, __asan_report_store8)(void *addr);
779ASAN_ALIAS(__asan_report_store16_noabort, __asan_report_store16)(void *addr);
780ASAN_ALIAS(__asan_report_load_n_noabort, __asan_report_load_n)(void *addr,
781 size_t size);
782ASAN_ALIAS(__asan_report_store_n_noabort, __asan_report_store_n)(void *addr,
783 size_t size);
784#endif
785