diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2022-09-16 07:41:30 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2022-09-16 07:41:30 +0300 |
commit | ed52814448645759ac14b383969447bf239cc1f4 (patch) | |
tree | 9319c2044a5194c409c40e858d6f867df984a8e6 /mark.c | |
parent | 213e4b3b3ff54851034239476d4ec845e10b4770 (diff) | |
download | bdwgc-ed52814448645759ac14b383969447bf239cc1f4.tar.gz |
Avoid potential race between realloc and GC_block_was_dirty
GC_realloc might be changing the block size while GC_block_was_dirty
is examining it. The change to the size field is benign, in that
GC_block_was_dirty would work correctly with either value, since we
are not changing the number of objects in the block. But seeing
a half-updated value (though unlikely to occur in practice) could be
probably bad. Using unordered atomic accesses on the size field
should solve the issue.
* mark.c [!GC_DISABLE_INCREMENTAL && AO_HAVE_load]
(GC_block_was_dirty): Use AO_load() to get hhdr->hb_sz value; add
comment.
Diffstat (limited to 'mark.c')
-rw-r--r-- | mark.c | 8 |
1 files changed, 7 insertions, 1 deletions
@@ -1962,9 +1962,15 @@ STATIC void GC_push_marked(struct hblk *h, hdr *hhdr) /* Test whether any page in the given block is dirty. */ STATIC GC_bool GC_block_was_dirty(struct hblk *h, hdr *hhdr) { - word sz = hhdr -> hb_sz; + word sz; ptr_t p; +# ifdef AO_HAVE_load + /* Atomic access is used to avoid racing with GC_realloc. */ + sz = (word)AO_load((volatile AO_t *)&(hhdr -> hb_sz)); +# else + sz = hhdr -> hb_sz; +# endif if (sz <= MAXOBJBYTES) { return GC_page_was_dirty(h); } |