From 92e3c595753cd301a12e97e015aabf6dcd2405b3 Mon Sep 17 00:00:00 2001 From: Mark Probst Date: Mon, 27 Apr 2015 17:31:46 -0700 Subject: [PATCH] [sgen] Fix a card table bug on 64 bits. When copying value types (like via Array.Copy) it was possible to encounter a memory region going over the end of the card table array. In that case we would overwrite data after the card table and fail to mark cards at the start of the array. It's hard to do a test case for this because we allocate the shadow card table directly after the regular one, so the overwrite is benign. It would also require allocating very large arrays (>2Gb) and run very slowly. --- mono/metadata/sgen-cardtable.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/mono/metadata/sgen-cardtable.c b/mono/metadata/sgen-cardtable.c index 6f852df9577..1d66fde4979 100644 --- a/mono/metadata/sgen-cardtable.c +++ b/mono/metadata/sgen-cardtable.c @@ -253,7 +253,24 @@ sgen_card_table_align_pointer (void *ptr) void sgen_card_table_mark_range (mword address, mword size) { - memset (sgen_card_table_get_card_address (address), 1, cards_in_range (address, size)); + mword num_cards = cards_in_range (address, size); + guint8 *start = sgen_card_table_get_card_address (address); + +#ifdef SGEN_HAVE_OVERLAPPING_CARDS + /* + * FIXME: There's a theoretical bug here, namely that the card table is allocated so + * far toward the end of the address space that start + num_cards overflows. + */ + guint8 *end = start + num_cards; + SGEN_ASSERT (0, num_cards <= CARD_COUNT_IN_BYTES, "How did we get an object larger than the card table?"); + if (end > SGEN_CARDTABLE_END) { + memset (start, 1, SGEN_CARDTABLE_END - start); + memset (sgen_cardtable, 1, end - sgen_cardtable); + return; + } +#endif + + memset (start, 1, num_cards); } static gboolean -- 2.11.4.GIT