Skip to content

Compact normal form block allocation can race with GC initialization

While looking at !1603 (closed) I stumbled upon the following data race:

==================
WARNING: ThreadSanitizer: data race (pid=9105)
  Atomic read of size 8 at 0x7b5800000048 by thread T6:
    #0 __tsan_atomic64_load <null> (libtsan.so.0+0x00000006130c)
    #1 calcNeeded rts/sm/Storage.c:1294 (compact_mutable+0x00000075c945)
    #2 scheduleDoGC rts/Schedule.c:1549 (compact_mutable+0x00000072f361)
    #3 schedule rts/Schedule.c:255 (compact_mutable+0x000000731722)
    #4 scheduleWorker rts/Schedule.c:2576 (compact_mutable+0x000000733dce)
    #5 workerStart rts/Task.c:445 (compact_mutable+0x00000073a9e5)
    #6 <null> <null> (libtsan.so.0+0x000000028d5b)

  Previous write of size 8 at 0x7b5800000048 by main thread (mutexes: write M16):
    #0 compactAllocateBlockInternal rts/sm/CNF.c:209 (compact_mutable+0x000000780661)
    #1 compactNew rts/sm/CNF.c:372 (compact_mutable+0x000000780965)
    #2 stg_compactNewzh <null> (compact_mutable+0x000000761ceb)
    #3 scheduleWaitThread rts/Schedule.c:2559 (compact_mutable+0x000000733d5d)
    #4 rts_evalLazyIO rts/RtsAPI.c:530 (compact_mutable+0x00000077b681)
    #5 hs_main rts/RtsMain.c:72 (compact_mutable+0x00000072b3e5)
    #6 main <null> (compact_mutable+0x000000412da5)

  Location is heap block of size 768 at 0x7b5800000000 allocated by main thread:
    #0 malloc <null> (libtsan.so.0+0x00000002b251)
    #1 stgMallocBytes rts/RtsUtils.c:64 (compact_mutable+0x00000072c63b)
    #2 initStorage rts/sm/Storage.c:154 (compact_mutable+0x000000759b40)
    #3 hs_init_ghc rts/RtsStartup.c:245 (compact_mutable+0x00000072c210)
    #4 hs_main rts/RtsMain.c:57 (compact_mutable+0x00000072b3bb)
    #5 main <null> (compact_mutable+0x000000412da5)

  Mutex M16 (0x0000009127c0) created at:
    #0 pthread_mutex_init <null> (libtsan.so.0+0x00000002c81e)
    #1 initMutex rts/posix/OSThreads.c:170 (compact_mutable+0x00000075f937)
    #2 initStorage rts/sm/Storage.c:148 (compact_mutable+0x000000759b0b)
    #3 hs_init_ghc rts/RtsStartup.c:245 (compact_mutable+0x00000072c210)
    #4 hs_main rts/RtsMain.c:57 (compact_mutable+0x00000072b3bb)
    #5 main <null> (compact_mutable+0x000000412da5)

  Thread T6 (tid=9112, running) created by thread T5 at:
    #0 pthread_create <null> (libtsan.so.0+0x00000002c010)
    #1 createOSThread rts/posix/OSThreads.c:137 (compact_mutable+0x00000075f8af)
    #2 startWorkerTask rts/Task.c:497 (compact_mutable+0x00000073b3fa)
    #3 releaseCapability_ rts/Capability.c:567 (compact_mutable+0x000000725367)
    #4 suspendThread rts/Schedule.c:2424 (compact_mutable+0x0000007335b4)
    #5 <null> <null> (compact_mutable+0x00000068e541)
    #6 scheduleWorker rts/Schedule.c:2576 (compact_mutable+0x000000733dce)
    #7 workerStart rts/Task.c:445 (compact_mutable+0x00000073a9e5)
    #8 <null> <null> (libtsan.so.0+0x000000028d5b)

SUMMARY: ThreadSanitizer: data race (/nix/store/c7hj2bk4aqgpb3q0h5xhq7lag0lq3jm7-gcc-7.4.0-lib/lib/libtsan.so.0+0x6130c) in __tsan_atomic64_load                  

compactAllocateBlockInternal updates generation->n_compact_blocks while holding SM_LOCK yet calcNeeded doesn't bother to take SM_LOCK itself.

Arguably this isn't the end of the world resulting in only a slight change in GC timing.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information