Cheng Shao pushed to branch wip/terrorjack/asan at Glasgow Haskell Compiler / GHC
Commits:
-
bf610931
by Cheng Shao at 2026-07-04T11:31:23+00:00
-
2dfcb8f1
by Cheng Shao at 2026-07-04T11:32:07+00:00
-
a9b83253
by Cheng Shao at 2026-07-04T11:32:43+00:00
-
a128cddc
by Cheng Shao at 2026-07-04T11:33:18+00:00
-
26da344a
by Cheng Shao at 2026-07-04T11:33:47+00:00
-
453c1e8a
by Cheng Shao at 2026-07-04T11:34:17+00:00
-
6ba98fc8
by Cheng Shao at 2026-07-04T11:34:46+00:00
9 changed files:
- rts/Hash.c
- rts/Task.c
- rts/include/Stg.h
- + rts/include/rts/ASANUtils.h
- rts/rts.cabal
- rts/sm/BlockAlloc.c
- rts/sm/GCUtils.c
- rts/sm/MBlock.c
- rts/sm/Storage.c
Changes:
| ... | ... | @@ -283,6 +283,7 @@ allocHashList (HashTable *table) |
| 283 | 283 | if (table->freeList != NULL) {
|
| 284 | 284 | HashList *hl = table->freeList;
|
| 285 | 285 | table->freeList = hl->next;
|
| 286 | + __asan_unpoison_memory_region(hl, offsetof(HashList, next));
|
|
| 286 | 287 | return hl;
|
| 287 | 288 | } else {
|
| 288 | 289 | /* We allocate one block of memory which contains:
|
| ... | ... | @@ -302,8 +303,11 @@ allocHashList (HashTable *table) |
| 302 | 303 | |
| 303 | 304 | table->freeList = hl + 1;
|
| 304 | 305 | HashList *p = table->freeList;
|
| 305 | - for (; p < hl + HCHUNK - 1; p++)
|
|
| 306 | + for (; p < hl + HCHUNK - 1; p++) {
|
|
| 307 | + __asan_poison_memory_region(p, offsetof(HashList, next));
|
|
| 306 | 308 | p->next = p + 1;
|
| 309 | + }
|
|
| 310 | + __asan_poison_memory_region(p, offsetof(HashList, next));
|
|
| 307 | 311 | p->next = NULL;
|
| 308 | 312 | return hl;
|
| 309 | 313 | }
|
| ... | ... | @@ -318,6 +322,7 @@ freeHashList (HashTable *table, HashList *hl) |
| 318 | 322 | // HashListChunks.
|
| 319 | 323 | hl->next = table->freeList;
|
| 320 | 324 | table->freeList = hl;
|
| 325 | + __asan_poison_memory_region(hl, offsetof(HashList, next));
|
|
| 321 | 326 | }
|
| 322 | 327 | |
| 323 | 328 | STATIC_INLINE void
|
| ... | ... | @@ -388,9 +393,10 @@ removeHashTable_inlined(HashTable *table, StgWord key, const void *data, |
| 388 | 393 | table->dir[segment][index] = hl->next;
|
| 389 | 394 | else
|
| 390 | 395 | prev->next = hl->next;
|
| 396 | + void *hl_data = (void*)hl->data;
|
|
| 391 | 397 | freeHashList(table,hl);
|
| 392 | 398 | table->kcount--;
|
| 393 | - return (void *) hl->data;
|
|
| 399 | + return hl_data;
|
|
| 394 | 400 | }
|
| 395 | 401 | prev = hl;
|
| 396 | 402 | }
|
| ... | ... | @@ -183,6 +183,7 @@ freeTask (Task *task) |
| 183 | 183 | stgFree(incall);
|
| 184 | 184 | }
|
| 185 | 185 | for (incall = task->spare_incalls; incall != NULL; incall = next) {
|
| 186 | + __asan_unpoison_memory_region(incall, sizeof(InCall));
|
|
| 186 | 187 | next = incall->next;
|
| 187 | 188 | stgFree(incall);
|
| 188 | 189 | }
|
| ... | ... | @@ -252,6 +253,7 @@ newInCall (Task *task) |
| 252 | 253 | |
| 253 | 254 | if (task->spare_incalls != NULL) {
|
| 254 | 255 | incall = task->spare_incalls;
|
| 256 | + __asan_unpoison_memory_region(incall, sizeof(InCall));
|
|
| 255 | 257 | task->spare_incalls = incall->next;
|
| 256 | 258 | task->n_spare_incalls--;
|
| 257 | 259 | } else {
|
| ... | ... | @@ -283,6 +285,7 @@ endInCall (Task *task) |
| 283 | 285 | stgFree(incall);
|
| 284 | 286 | } else {
|
| 285 | 287 | incall->next = task->spare_incalls;
|
| 288 | + __asan_poison_memory_region(incall, sizeof(InCall));
|
|
| 286 | 289 | task->spare_incalls = incall;
|
| 287 | 290 | task->n_spare_incalls++;
|
| 288 | 291 | }
|
| ... | ... | @@ -331,6 +331,7 @@ external prototype return neither of these types to workaround #11395. |
| 331 | 331 | #include "stg/MachRegsForHost.h"
|
| 332 | 332 | #include "stg/Regs.h"
|
| 333 | 333 | #include "stg/Ticky.h"
|
| 334 | +#include "rts/ASANUtils.h"
|
|
| 334 | 335 | #include "rts/TSANUtils.h"
|
| 335 | 336 | |
| 336 | 337 | #if IN_STG_CODE
|
| 1 | +#pragma once
|
|
| 2 | + |
|
| 3 | +#if defined(__SANITIZE_ADDRESS__)
|
|
| 4 | +#define ASAN_ENABLED
|
|
| 5 | +#elif defined(__has_feature)
|
|
| 6 | +#if __has_feature(address_sanitizer)
|
|
| 7 | +#define ASAN_ENABLED
|
|
| 8 | +#endif
|
|
| 9 | +#endif
|
|
| 10 | + |
|
| 11 | +#if defined(ASAN_ENABLED)
|
|
| 12 | +#include <sanitizer/asan_interface.h>
|
|
| 13 | +#else
|
|
| 14 | + |
|
| 15 | +#include <stdlib.h>
|
|
| 16 | + |
|
| 17 | +static inline void __asan_poison_memory_region(void const volatile *addr
|
|
| 18 | + __attribute__((unused)),
|
|
| 19 | + size_t size
|
|
| 20 | + __attribute__((unused))) {}
|
|
| 21 | + |
|
| 22 | +static inline void __asan_unpoison_memory_region(void const volatile *addr
|
|
| 23 | + __attribute__((unused)),
|
|
| 24 | + size_t size
|
|
| 25 | + __attribute__((unused))) {}
|
|
| 26 | + |
|
| 27 | +#endif |
| ... | ... | @@ -292,6 +292,7 @@ library |
| 292 | 292 | -- ^ generated
|
| 293 | 293 | rts/ghc_ffi.h
|
| 294 | 294 | rts/Adjustor.h
|
| 295 | + rts/ASANUtils.h
|
|
| 295 | 296 | rts/ExecPage.h
|
| 296 | 297 | rts/BlockSignals.h
|
| 297 | 298 | rts/Bytecodes.h
|
| ... | ... | @@ -261,6 +261,8 @@ initGroup(bdescr *head) |
| 261 | 261 | head[i].flags = 0;
|
| 262 | 262 | }
|
| 263 | 263 | #endif
|
| 264 | + |
|
| 265 | + __asan_unpoison_memory_region(head->start, (W_)head->blocks * BLOCK_SIZE);
|
|
| 264 | 266 | }
|
| 265 | 267 | |
| 266 | 268 | #if SIZEOF_VOID_P == SIZEOF_LONG
|
| ... | ... | @@ -474,6 +476,7 @@ alloc_mega_group (uint32_t node, StgWord mblocks) |
| 474 | 476 | bd = alloc_mega_group_from_free_list(&deferred_free_mblock_list[node], n, &best);
|
| 475 | 477 | if(bd)
|
| 476 | 478 | {
|
| 479 | + __asan_unpoison_memory_region(bd->start, (W_)bd->blocks * BLOCK_SIZE);
|
|
| 477 | 480 | return bd;
|
| 478 | 481 | }
|
| 479 | 482 | else if(!best)
|
| ... | ... | @@ -490,6 +493,7 @@ alloc_mega_group (uint32_t node, StgWord mblocks) |
| 490 | 493 | |
| 491 | 494 | if (bd)
|
| 492 | 495 | {
|
| 496 | + __asan_unpoison_memory_region(bd->start, (W_)bd->blocks * BLOCK_SIZE);
|
|
| 493 | 497 | return bd;
|
| 494 | 498 | }
|
| 495 | 499 | else if (best)
|
| ... | ... | @@ -500,6 +504,7 @@ alloc_mega_group (uint32_t node, StgWord mblocks) |
| 500 | 504 | (best_mblocks-mblocks)*MBLOCK_SIZE);
|
| 501 | 505 | |
| 502 | 506 | best->blocks = MBLOCK_GROUP_BLOCKS(best_mblocks - mblocks);
|
| 507 | + __asan_unpoison_memory_region(MBLOCK_ROUND_DOWN(bd), mblocks * MBLOCK_SIZE);
|
|
| 503 | 508 | initMBlock(MBLOCK_ROUND_DOWN(bd), node);
|
| 504 | 509 | }
|
| 505 | 510 | else
|
| ... | ... | @@ -880,6 +885,8 @@ free_mega_group (bdescr *mg) |
| 880 | 885 | |
| 881 | 886 | IF_DEBUG(sanity, checkFreeListSanity());
|
| 882 | 887 | }
|
| 888 | + |
|
| 889 | + __asan_poison_memory_region(mg->start, (W_)mg->blocks * BLOCK_SIZE);
|
|
| 883 | 890 | }
|
| 884 | 891 | |
| 885 | 892 | static void
|
| ... | ... | @@ -927,6 +934,8 @@ free_deferred_mega_groups (uint32_t node) |
| 927 | 934 | // coalesce forwards
|
| 928 | 935 | coalesce_mblocks(mg);
|
| 929 | 936 | |
| 937 | + __asan_poison_memory_region(mg->start, (W_)mg->blocks * BLOCK_SIZE);
|
|
| 938 | + |
|
| 930 | 939 | // initialize search for next round
|
| 931 | 940 | prev = mg;
|
| 932 | 941 | bd = prev->link;
|
| ... | ... | @@ -1050,6 +1059,8 @@ freeGroup(bdescr *p) |
| 1050 | 1059 | setup_tail(p);
|
| 1051 | 1060 | free_list_insert(node,p);
|
| 1052 | 1061 | |
| 1062 | + __asan_poison_memory_region(p->start, (W_)p->blocks * BLOCK_SIZE);
|
|
| 1063 | + |
|
| 1053 | 1064 | IF_DEBUG(sanity, checkFreeListSanity());
|
| 1054 | 1065 | }
|
| 1055 | 1066 |
| ... | ... | @@ -348,6 +348,7 @@ alloc_todo_block (gen_workspace *ws, uint32_t size) |
| 348 | 348 | } else {
|
| 349 | 349 | if (gct->free_blocks) {
|
| 350 | 350 | bd = gct->free_blocks;
|
| 351 | + __asan_unpoison_memory_region(bd->start, (W_)bd->blocks * BLOCK_SIZE);
|
|
| 351 | 352 | gct->free_blocks = bd->link;
|
| 352 | 353 | } else {
|
| 353 | 354 | // We allocate in chunks of at most 16 blocks, use one
|
| ... | ... | @@ -357,6 +358,9 @@ alloc_todo_block (gen_workspace *ws, uint32_t size) |
| 357 | 358 | StgWord n_blocks = stg_min(chunk_size, 1 << (MBLOCK_SHIFT - BLOCK_SHIFT - 1));
|
| 358 | 359 | allocBlocks_sync(n_blocks, &bd);
|
| 359 | 360 | gct->free_blocks = bd->link;
|
| 361 | + for (bdescr *bd = gct->free_blocks; bd; bd = bd->link) {
|
|
| 362 | + __asan_poison_memory_region(bd->start, (W_)bd->blocks * BLOCK_SIZE);
|
|
| 363 | + }
|
|
| 360 | 364 | }
|
| 361 | 365 | }
|
| 362 | 366 | initBdescr(bd, ws->gen, ws->gen->to);
|
| ... | ... | @@ -641,6 +641,8 @@ getMBlocks(uint32_t n) |
| 641 | 641 | |
| 642 | 642 | ret = getCommittedMBlocks(n);
|
| 643 | 643 | |
| 644 | + __asan_unpoison_memory_region(ret, (W_)n * MBLOCK_SIZE);
|
|
| 645 | + |
|
| 644 | 646 | debugTrace(DEBUG_gc, "allocated %d megablock(s) at %p",n,ret);
|
| 645 | 647 | |
| 646 | 648 | mblocks_allocated += n;
|
| ... | ... | @@ -673,6 +675,8 @@ freeMBlocks(void *addr, uint32_t n) |
| 673 | 675 | |
| 674 | 676 | mblocks_allocated -= n;
|
| 675 | 677 | |
| 678 | + __asan_poison_memory_region(addr, (W_)n * MBLOCK_SIZE);
|
|
| 679 | + |
|
| 676 | 680 | decommitMBlocks(addr, n);
|
| 677 | 681 | }
|
| 678 | 682 |
| ... | ... | @@ -1242,6 +1242,10 @@ start_new_pinned_block(Capability *cap) |
| 1242 | 1242 | ACQUIRE_SM_LOCK;
|
| 1243 | 1243 | bd = allocNursery(cap->node, NULL, PINNED_EMPTY_SIZE);
|
| 1244 | 1244 | RELEASE_SM_LOCK;
|
| 1245 | + |
|
| 1246 | + for (bdescr *pbd = bd; pbd; pbd = pbd->link) {
|
|
| 1247 | + __asan_poison_memory_region(pbd->start, (W_)pbd->blocks * BLOCK_SIZE);
|
|
| 1248 | + }
|
|
| 1245 | 1249 | }
|
| 1246 | 1250 | |
| 1247 | 1251 | // Bump up the nursery pointer to avoid the pathological situation
|
| ... | ... | @@ -1267,6 +1271,7 @@ start_new_pinned_block(Capability *cap) |
| 1267 | 1271 | }
|
| 1268 | 1272 | |
| 1269 | 1273 | cap->pinned_object_empty = bd->link;
|
| 1274 | + __asan_unpoison_memory_region(bd->start, (W_)bd->blocks * BLOCK_SIZE);
|
|
| 1270 | 1275 | newNurseryBlock(bd);
|
| 1271 | 1276 | if (bd->link != NULL) {
|
| 1272 | 1277 | bd->link->u.back = cap->pinned_object_empty;
|