diff options
| author | Paul Eggert | 2020-08-14 14:33:21 -0700 |
|---|---|---|
| committer | Paul Eggert | 2020-08-14 15:51:52 -0700 |
| commit | 4ecc2ba01db5029c42d3b7f1418a021cccf2dc67 (patch) | |
| tree | dbddc98222b1fbdb7d3af0f373d21fb3b2c73467 /src | |
| parent | ca6c3bec0769d8ac7a49cdb8d2580add5485366e (diff) | |
| download | emacs-4ecc2ba01db5029c42d3b7f1418a021cccf2dc67.tar.gz emacs-4ecc2ba01db5029c42d3b7f1418a021cccf2dc67.zip | |
Fix bus error on Debian bullseye
Problem reported by Lars Ingebrigtsen, and problem diagnosis
and most of this patch by Pip Cet (Bug#42832).
* src/pdumper.c (dump_bitsets_init): Rename from dump_bitset_init.
All callers changed. Initialize two bitsets with a single malloc
call.
(struct pdumper_loaded_dump_private): New member last_mark_bits.
(pdumper_find_object_type_impl): Return PDUMPER_NO_OBJECT if
the last_mark_bits’ bit is clear.
(pdumper_set_marked_impl): Assert that the last_mark_bits’
bit is set.
(pdumper_clear_marks_impl): Save mark_bits into
last_mark_bits before clearing mark_bits.
Co-authored-by: Pip Cet <pipcet@gmail.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/pdumper.c | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/src/pdumper.c b/src/pdumper.c index bc41afc7c5a..2d1b19283c7 100644 --- a/src/pdumper.c +++ b/src/pdumper.c | |||
| @@ -4802,14 +4802,19 @@ struct dump_bitset | |||
| 4802 | }; | 4802 | }; |
| 4803 | 4803 | ||
| 4804 | static bool | 4804 | static bool |
| 4805 | dump_bitset_init (struct dump_bitset *bitset, size_t number_bits) | 4805 | dump_bitsets_init (struct dump_bitset bitset[2], size_t number_bits) |
| 4806 | { | 4806 | { |
| 4807 | int xword_size = sizeof (bitset->bits[0]); | 4807 | int xword_size = sizeof (bitset[0].bits[0]); |
| 4808 | int bits_per_word = xword_size * CHAR_BIT; | 4808 | int bits_per_word = xword_size * CHAR_BIT; |
| 4809 | ptrdiff_t words_needed = divide_round_up (number_bits, bits_per_word); | 4809 | ptrdiff_t words_needed = divide_round_up (number_bits, bits_per_word); |
| 4810 | bitset->number_words = words_needed; | 4810 | dump_bitset_word *bits = calloc (words_needed, 2 * xword_size); |
| 4811 | bitset->bits = calloc (words_needed, xword_size); | 4811 | if (!bits) |
| 4812 | return bitset->bits != NULL; | 4812 | return false; |
| 4813 | bitset[0].bits = bits; | ||
| 4814 | bitset[0].number_words = bitset[1].number_words = words_needed; | ||
| 4815 | bitset[1].bits = memset (bits + words_needed, UCHAR_MAX, | ||
| 4816 | words_needed * xword_size); | ||
| 4817 | return true; | ||
| 4813 | } | 4818 | } |
| 4814 | 4819 | ||
| 4815 | static dump_bitset_word * | 4820 | static dump_bitset_word * |
| @@ -4870,7 +4875,7 @@ struct pdumper_loaded_dump_private | |||
| 4870 | /* Copy of the header we read from the dump. */ | 4875 | /* Copy of the header we read from the dump. */ |
| 4871 | struct dump_header header; | 4876 | struct dump_header header; |
| 4872 | /* Mark bits for objects in the dump; used during GC. */ | 4877 | /* Mark bits for objects in the dump; used during GC. */ |
| 4873 | struct dump_bitset mark_bits; | 4878 | struct dump_bitset mark_bits, last_mark_bits; |
| 4874 | /* Time taken to load the dump. */ | 4879 | /* Time taken to load the dump. */ |
| 4875 | double load_time; | 4880 | double load_time; |
| 4876 | /* Dump file name. */ | 4881 | /* Dump file name. */ |
| @@ -4993,6 +4998,10 @@ pdumper_find_object_type_impl (const void *obj) | |||
| 4993 | dump_off offset = ptrdiff_t_to_dump_off ((uintptr_t) obj - dump_public.start); | 4998 | dump_off offset = ptrdiff_t_to_dump_off ((uintptr_t) obj - dump_public.start); |
| 4994 | if (offset % DUMP_ALIGNMENT != 0) | 4999 | if (offset % DUMP_ALIGNMENT != 0) |
| 4995 | return PDUMPER_NO_OBJECT; | 5000 | return PDUMPER_NO_OBJECT; |
| 5001 | ptrdiff_t bitno = offset / DUMP_ALIGNMENT; | ||
| 5002 | if (offset < dump_private.header.cold_start | ||
| 5003 | && !dump_bitset_bit_set_p (&dump_private.last_mark_bits, bitno)) | ||
| 5004 | return PDUMPER_NO_OBJECT; | ||
| 4996 | const struct dump_reloc *reloc = | 5005 | const struct dump_reloc *reloc = |
| 4997 | dump_find_relocation (&dump_private.header.object_starts, offset); | 5006 | dump_find_relocation (&dump_private.header.object_starts, offset); |
| 4998 | return (reloc != NULL && dump_reloc_get_offset (*reloc) == offset) | 5007 | return (reloc != NULL && dump_reloc_get_offset (*reloc) == offset) |
| @@ -5021,12 +5030,16 @@ pdumper_set_marked_impl (const void *obj) | |||
| 5021 | eassert (offset < dump_private.header.cold_start); | 5030 | eassert (offset < dump_private.header.cold_start); |
| 5022 | eassert (offset < dump_private.header.discardable_start); | 5031 | eassert (offset < dump_private.header.discardable_start); |
| 5023 | ptrdiff_t bitno = offset / DUMP_ALIGNMENT; | 5032 | ptrdiff_t bitno = offset / DUMP_ALIGNMENT; |
| 5033 | eassert (dump_bitset_bit_set_p (&dump_private.last_mark_bits, bitno)); | ||
| 5024 | dump_bitset_set_bit (&dump_private.mark_bits, bitno); | 5034 | dump_bitset_set_bit (&dump_private.mark_bits, bitno); |
| 5025 | } | 5035 | } |
| 5026 | 5036 | ||
| 5027 | void | 5037 | void |
| 5028 | pdumper_clear_marks_impl (void) | 5038 | pdumper_clear_marks_impl (void) |
| 5029 | { | 5039 | { |
| 5040 | dump_bitset_word *swap = dump_private.last_mark_bits.bits; | ||
| 5041 | dump_private.last_mark_bits.bits = dump_private.mark_bits.bits; | ||
| 5042 | dump_private.mark_bits.bits = swap; | ||
| 5030 | dump_bitset_clear (&dump_private.mark_bits); | 5043 | dump_bitset_clear (&dump_private.mark_bits); |
| 5031 | } | 5044 | } |
| 5032 | 5045 | ||
| @@ -5243,7 +5256,7 @@ pdumper_load (const char *dump_filename) | |||
| 5243 | int dump_page_size; | 5256 | int dump_page_size; |
| 5244 | dump_off adj_discardable_start; | 5257 | dump_off adj_discardable_start; |
| 5245 | 5258 | ||
| 5246 | struct dump_bitset mark_bits; | 5259 | struct dump_bitset mark_bits[2]; |
| 5247 | size_t mark_bits_needed; | 5260 | size_t mark_bits_needed; |
| 5248 | 5261 | ||
| 5249 | struct dump_header header_buf = { 0 }; | 5262 | struct dump_header header_buf = { 0 }; |
| @@ -5357,7 +5370,7 @@ pdumper_load (const char *dump_filename) | |||
| 5357 | err = PDUMPER_LOAD_ERROR; | 5370 | err = PDUMPER_LOAD_ERROR; |
| 5358 | mark_bits_needed = | 5371 | mark_bits_needed = |
| 5359 | divide_round_up (header->discardable_start, DUMP_ALIGNMENT); | 5372 | divide_round_up (header->discardable_start, DUMP_ALIGNMENT); |
| 5360 | if (!dump_bitset_init (&mark_bits, mark_bits_needed)) | 5373 | if (!dump_bitsets_init (mark_bits, mark_bits_needed)) |
| 5361 | goto out; | 5374 | goto out; |
| 5362 | 5375 | ||
| 5363 | /* Point of no return. */ | 5376 | /* Point of no return. */ |
| @@ -5365,7 +5378,8 @@ pdumper_load (const char *dump_filename) | |||
| 5365 | dump_base = (uintptr_t) sections[DS_HOT].mapping; | 5378 | dump_base = (uintptr_t) sections[DS_HOT].mapping; |
| 5366 | gflags.dumped_with_pdumper_ = true; | 5379 | gflags.dumped_with_pdumper_ = true; |
| 5367 | dump_private.header = *header; | 5380 | dump_private.header = *header; |
| 5368 | dump_private.mark_bits = mark_bits; | 5381 | dump_private.mark_bits = mark_bits[0]; |
| 5382 | dump_private.last_mark_bits = mark_bits[1]; | ||
| 5369 | dump_public.start = dump_base; | 5383 | dump_public.start = dump_base; |
| 5370 | dump_public.end = dump_public.start + dump_size; | 5384 | dump_public.end = dump_public.start + dump_size; |
| 5371 | 5385 | ||