diff options
author | Ben Gamari <ben@smart-cactus.org> | 2023-01-16 11:46:09 -0500 |
---|---|---|
committer | Cheng Shao <terrorjack@type.dance> | 2023-05-08 12:15:19 +0000 |
commit | 3e3a6be4023189b2d637beda240e23fa9e856810 (patch) | |
tree | 580ce4ea0256d1f892dc04b3194c756810437d4a | |
parent | 994bda563604461ffb8454d6e298b0310520bcc8 (diff) | |
download | haskell-3e3a6be4023189b2d637beda240e23fa9e856810.tar.gz |
rts: Fix data-race in hs_init_ghcwip/T22756
As noticed by @Terrorjack, `hs_init_ghc` previously used non-atomic
increment/decrement on the RTS's initialization count. This may go wrong
in a multithreaded program which initializes the runtime multiple times.
Closes #22756.
-rw-r--r-- | rts/RtsStartup.c | 19 |
1 files changed, 11 insertions, 8 deletions
diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c index 5cb94c71e8..cfbd0421f5 100644 --- a/rts/RtsStartup.c +++ b/rts/RtsStartup.c @@ -68,7 +68,7 @@ #endif // Count of how many outstanding hs_init()s there have been. -static int hs_init_count = 0; +static StgWord hs_init_count = 0; static bool rts_shutdown = false; #if defined(mingw32_HOST_OS) @@ -242,8 +242,9 @@ hs_init_with_rtsopts(int *argc, char **argv[]) void hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config) { - hs_init_count++; - if (hs_init_count > 1) { + // N.B. atomic_inc returns the new value. + StgWord init_count = atomic_inc(&hs_init_count, 1); + if (init_count > 1) { // second and subsequent inits are ignored return; } @@ -452,15 +453,17 @@ hs_exit_(bool wait_foreign) { uint32_t g, i; - if (hs_init_count <= 0) { - errorBelch("warning: too many hs_exit()s"); + // N.B. atomic_dec returns the new value. + StgInt init_count = (StgInt)atomic_dec(&hs_init_count); + if (init_count > 0) { + // ignore until it's the last one return; } - hs_init_count--; - if (hs_init_count > 0) { - // ignore until it's the last one + if (init_count < 0) { + errorBelch("warning: too many hs_exit()s"); return; } + rts_shutdown = true; /* start timing the shutdown */ |