summaryrefslogtreecommitdiff
path: root/mark.c
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2022-09-16 07:41:30 +0300
committerIvan Maidanski <ivmai@mail.ru>2022-09-16 07:41:30 +0300
commited52814448645759ac14b383969447bf239cc1f4 (patch)
tree9319c2044a5194c409c40e858d6f867df984a8e6 /mark.c
parent213e4b3b3ff54851034239476d4ec845e10b4770 (diff)
downloadbdwgc-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.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/mark.c b/mark.c
index 9f39af5c..f33ec90c 100644
--- a/mark.c
+++ b/mark.c
@@ -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);
}