aboutsummaryrefslogtreecommitdiffstats
path: root/src/alloc.c
diff options
context:
space:
mode:
authorVibhav Pant2022-12-19 18:04:05 +0530
committerVibhav Pant2022-12-19 18:04:05 +0530
commitcb242bf1514ade34ab93b1db1ea7550093ae5839 (patch)
tree05b066f7a16dcba316bb34923bf64a92dca97204 /src/alloc.c
parent79b1dede3444c07f943be34867bb2cdac236ab55 (diff)
downloademacs-cb242bf1514ade34ab93b1db1ea7550093ae5839.tar.gz
emacs-cb242bf1514ade34ab93b1db1ea7550093ae5839.zip
Add support for additional memory checks using AddressSanitizer.
When Emacs is compiled with AddressSanitizer support, enable poisoning/unpoisoning freed/unused Lisp objects and other internal memory management structures. If enabled, this will mark freed bytes that have been put on free lists for future use and initially allocated memory blocks/chunks as "poisoned", triggering an ASan error if they are accessed improperly. Structures are unpoisoned when they have been taken off their respective free lists. Additionally, add optional macros for performing unaligned loads, which when enabled by defining USE_SANITIZER_UNALIGNED_LOAD will use ASan provided functions for loading from unaligned addresses, which may help catch bugs that AddressSanitizer might otherwise miss. * configure.ac: Check for the existence of address and common sanitizer API headers. * src/lisp.h (UNALIGNED_LOAD_SIZE): New macro. If enabled, and the necessary sanitizer API is available, define it to __sanitizer_unaligned_load(64|32) depending on the word size of the architecture. * src/fns.c [HAVE_FAST_UNALIGNED_ACCESS] (Fstring_lessp): Use 'UNALIGNED_LOAD_SIZE' to perform unaligned loads from the two strings. * src/alloc.c (ASAN_POISON_ABLOCK, ASAN_UNPOISON_ABLOCK) (ASAN_POISON_INTERVAL_BLOCK, ASAN_UNPOISON_INTERVAL_BLOCK) (ASAN_POISON_INTERVAL, ASAN_UNPOISON_INTERVAL) (ASAN_PREPARE_DEAD_SDATA, ASAN_PREPARE_LIVE_SDATA) (ASAN_POISON_SBLOCK_DATA, ASAN_POISON_STRING_BLOCK) (ASAN_UNPOISON_STRING_BLOCK, ASAN_POISON_STRING) (ASAN_UNPOISON_STRING, ASAN_POISON_FLOAT_BLOCK) (ASAN_UNPOISON_FLOAT_BLOCK, ASAN_POISON_FLOAT) (ASAN_UNPOISON_FLOAT, ASAN_POISON_CONS_BLOCK) (ASAN_POISON_CONS, ASAN_UNPOISON_CONS) (ASAN_POISON_VECTOR_CONTENTS, ASAN_UNPOISON_VECTOR_CONTENTS) (ASAN_UNPOISON_VECTOR_BLOCK, ASAN_POISON_SYMBOL_BLOCK) (ASAN_UNPOISON_SYMBOL_BLOCK, ASAN_POISON_SYMBOL) (ASAN_UNPOISON_SYMBOL) [ADDRESS_SANITIZER]: New macros. When address sanitization is enabled, define them to poison/unpoison objects. (lisp_align_malloc): Poison newly allocated blocks on `free_ablock', unpoison ablocks taken from it respectively. (lisp_align_free): Poison individual ablocks when they are put on the free list, unpoison them when an entire `ablocks' chunk is being freed. (make_interval): Poison interval blocks on initial allocation, unpoison individual intervals on allocation and removal from `interval_free_list'. (sweep_intervals): Unpoison interval blocks before sweeping, poison dead/unmarked intervals. (allocate_string): Poison string blocks on initial allocation, unpoison Lisp_Strings on removal from the free list. (allocate_string_data): Poison `sblock' data on initial allocation, unpoison individual `sdata' contents on allocation or removal from the free list. Call `ASAN_PREPARE_LIVE_SDATA' on the new `sdata' struct. (sweep_strings): Unpoison string blocks before sweeping them, poisoning dead strings and their sdata afterwards. (compact_small_strings): Call `ASAN_PREPARE_LIVE_DATA' on the `sdata' to where compacted strings to moved to. (pin_string): Call `ASAN_PREPARE_DEAD_SDATA' on `old_sdata'. (make_float): Poison float blocks on allocation, unpoisoning individual Lisp_Floats on allocation or removal from `float_free_list'. (sweep_floats): Unpoison float blocks before sweeping, poison dead/unmarked floats. (free_cons): Poison `ptr'. (Fcons): Poison cons blocks on allocation, unpoisoning individual Lisp_Cons on allocation or removal from `cons_free_list'. (sweep_conses): Poison dead/unmarked conses. (setup_free_list): Poison vectors put on `vector_free_lists'. (allocate_vector_from_block): Unpoison vectors taken from the free list, poison excess vector bytes when vectors allocated from the free list are larger than requested. (sweep_vectors): Unpoison vector blocks before sweeping them. (Fmake_symbol): Poison symbol blocks on initial allocation, unpoisoning individual Lisp_Symbols on allocation or removal from `symbol_free_list'. (sweep_symbols): Unpoison symbol blocks before sweeping, poisoning dead/unmarked symbols. (live_string_holding, live_cons_holding, live_symbol_holding) (live_float_holding): When compiling with address sanitization and GC poisoning enabled, return NULL if the passed address is poisoned, or if the Lisp object it resides in is poisoned, avoiding a use-after-poison trigger if these functions are called on a pointer that might be referring to a now dead/swept object. * etc/DEBUG: Add information about enabling ASan memory poisoning.
Diffstat (limited to 'src/alloc.c')
-rw-r--r--src/alloc.c271
1 files changed, 263 insertions, 8 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 82e8901cf43..2975754124a 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -80,6 +80,37 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
80#include <valgrind/memcheck.h> 80#include <valgrind/memcheck.h>
81#endif 81#endif
82 82
83/* AddressSanitizer exposes additional functions for manually marking
84 memory as poisoned/unpoisoned. When ASan is enabled and the needed
85 header is available, memory is poisoned when:
86
87 * An ablock is freed (lisp_align_free), or ablocks are initially
88 allocated (lisp_align_malloc).
89 * An interval_block is initially allocated (make_interval).
90 * A dead INTERVAL is put on the interval free list
91 (sweep_intervals).
92 * A sdata is marked as dead (sweep_strings, pin_string).
93 * An sblock is initially allocated (allocate_string_data).
94 * A string_block is initially allocated (allocate_string).
95 * A dead string is put on string_free_list (sweep_strings).
96 * A float_block is initially allocated (make_float).
97 * A dead float is put on float_free_list.
98 * A cons_block is initially allocated (Fcons).
99 * A dead cons is put on cons_free_list (sweep_cons).
100 * A dead vector is put on vector_free_list (setup_on_free_list),
101 or a new vector block is allocated (allocate_vector_from_block).
102 Accordingly, objects reused from the free list are unpoisoned.
103
104 This feature can be disabled wtih the run-time flag
105 `allow_user_poisoning' set to zero. */
106#if ADDRESS_SANITIZER && defined HAVE_SANITIZER_ASAN_INTERFACE_H \
107 && !defined GC_ASAN_POISON_OBJECTS
108# define GC_ASAN_POISON_OBJECTS 1
109# include <sanitizer/asan_interface.h>
110#else
111# define GC_ASAN_POISON_OBJECTS 0
112#endif
113
83/* GC_CHECK_MARKED_OBJECTS means do sanity checks on allocated objects. 114/* GC_CHECK_MARKED_OBJECTS means do sanity checks on allocated objects.
84 We turn that on by default when ENABLE_CHECKING is defined; 115 We turn that on by default when ENABLE_CHECKING is defined;
85 define GC_CHECK_MARKED_OBJECTS to zero to disable. */ 116 define GC_CHECK_MARKED_OBJECTS to zero to disable. */
@@ -1157,6 +1188,16 @@ struct ablocks
1157 (1 & (intptr_t) ABLOCKS_BUSY (abase) ? abase : ((void **) (abase))[-1]) 1188 (1 & (intptr_t) ABLOCKS_BUSY (abase) ? abase : ((void **) (abase))[-1])
1158#endif 1189#endif
1159 1190
1191#if GC_ASAN_POISON_OBJECTS
1192# define ASAN_POISON_ABLOCK(b) \
1193 __asan_poison_memory_region (&(b)->x, sizeof ((b)->x))
1194# define ASAN_UNPOISON_ABLOCK(b) \
1195 __asan_unpoison_memory_region (&(b)->x, sizeof ((b)->x))
1196#else
1197# define ASAN_POISON_ABLOCK(b) ((void) 0)
1198# define ASAN_UNPOISON_ABLOCK(b) ((void) 0)
1199#endif
1200
1160/* The list of free ablock. */ 1201/* The list of free ablock. */
1161static struct ablock *free_ablock; 1202static struct ablock *free_ablock;
1162 1203
@@ -1235,6 +1276,7 @@ lisp_align_malloc (size_t nbytes, enum mem_type type)
1235 { 1276 {
1236 abase->blocks[i].abase = abase; 1277 abase->blocks[i].abase = abase;
1237 abase->blocks[i].x.next_free = free_ablock; 1278 abase->blocks[i].x.next_free = free_ablock;
1279 ASAN_POISON_ABLOCK (&abase->blocks[i]);
1238 free_ablock = &abase->blocks[i]; 1280 free_ablock = &abase->blocks[i];
1239 } 1281 }
1240 intptr_t ialigned = aligned; 1282 intptr_t ialigned = aligned;
@@ -1247,6 +1289,7 @@ lisp_align_malloc (size_t nbytes, enum mem_type type)
1247 eassert ((intptr_t) ABLOCKS_BUSY (abase) == aligned); 1289 eassert ((intptr_t) ABLOCKS_BUSY (abase) == aligned);
1248 } 1290 }
1249 1291
1292 ASAN_UNPOISON_ABLOCK (free_ablock);
1250 abase = ABLOCK_ABASE (free_ablock); 1293 abase = ABLOCK_ABASE (free_ablock);
1251 ABLOCKS_BUSY (abase) 1294 ABLOCKS_BUSY (abase)
1252 = (struct ablocks *) (2 + (intptr_t) ABLOCKS_BUSY (abase)); 1295 = (struct ablocks *) (2 + (intptr_t) ABLOCKS_BUSY (abase));
@@ -1278,6 +1321,7 @@ lisp_align_free (void *block)
1278#endif 1321#endif
1279 /* Put on free list. */ 1322 /* Put on free list. */
1280 ablock->x.next_free = free_ablock; 1323 ablock->x.next_free = free_ablock;
1324 ASAN_POISON_ABLOCK (ablock);
1281 free_ablock = ablock; 1325 free_ablock = ablock;
1282 /* Update busy count. */ 1326 /* Update busy count. */
1283 intptr_t busy = (intptr_t) ABLOCKS_BUSY (abase) - 2; 1327 intptr_t busy = (intptr_t) ABLOCKS_BUSY (abase) - 2;
@@ -1290,9 +1334,12 @@ lisp_align_free (void *block)
1290 bool aligned = busy; 1334 bool aligned = busy;
1291 struct ablock **tem = &free_ablock; 1335 struct ablock **tem = &free_ablock;
1292 struct ablock *atop = &abase->blocks[aligned ? ABLOCKS_SIZE : ABLOCKS_SIZE - 1]; 1336 struct ablock *atop = &abase->blocks[aligned ? ABLOCKS_SIZE : ABLOCKS_SIZE - 1];
1293
1294 while (*tem) 1337 while (*tem)
1295 { 1338 {
1339#if GC_ASAN_POISON_OBJECTS
1340 __asan_unpoison_memory_region (&(*tem)->x,
1341 sizeof ((*tem)->x));
1342#endif
1296 if (*tem >= (struct ablock *) abase && *tem < atop) 1343 if (*tem >= (struct ablock *) abase && *tem < atop)
1297 { 1344 {
1298 i++; 1345 i++;
@@ -1421,6 +1468,24 @@ static int interval_block_index = INTERVAL_BLOCK_SIZE;
1421 1468
1422static INTERVAL interval_free_list; 1469static INTERVAL interval_free_list;
1423 1470
1471#if GC_ASAN_POISON_OBJECTS
1472# define ASAN_POISON_INTERVAL_BLOCK(b) \
1473 __asan_poison_memory_region ((b)->intervals, \
1474 sizeof ((b)->intervals))
1475# define ASAN_UNPOISON_INTERVAL_BLOCK(b) \
1476 __asan_unpoison_memory_region ((b)->intervals, \
1477 sizeof ((b)->intervals))
1478# define ASAN_POISON_INTERVAL(i) \
1479 __asan_poison_memory_region ((i), sizeof (*(i)))
1480# define ASAN_UNPOISON_INTERVAL(i) \
1481 __asan_unpoison_memory_region ((i), sizeof (*(i)))
1482#else
1483# define ASAN_POISON_INTERVAL_BLOCK(b) ((void) 0)
1484# define ASAN_UNPOISON_INTERVAL_BLOCK(b) ((void) 0)
1485# define ASAN_POISON_INTERVAL(i) ((void) 0)
1486# define ASAN_UNPOISON_INTERVAL(i) ((void) 0)
1487#endif
1488
1424/* Return a new interval. */ 1489/* Return a new interval. */
1425 1490
1426INTERVAL 1491INTERVAL
@@ -1433,6 +1498,7 @@ make_interval (void)
1433 if (interval_free_list) 1498 if (interval_free_list)
1434 { 1499 {
1435 val = interval_free_list; 1500 val = interval_free_list;
1501 ASAN_UNPOISON_INTERVAL (val);
1436 interval_free_list = INTERVAL_PARENT (interval_free_list); 1502 interval_free_list = INTERVAL_PARENT (interval_free_list);
1437 } 1503 }
1438 else 1504 else
@@ -1443,10 +1509,12 @@ make_interval (void)
1443 = lisp_malloc (sizeof *newi, false, MEM_TYPE_NON_LISP); 1509 = lisp_malloc (sizeof *newi, false, MEM_TYPE_NON_LISP);
1444 1510
1445 newi->next = interval_block; 1511 newi->next = interval_block;
1512 ASAN_POISON_INTERVAL_BLOCK (newi);
1446 interval_block = newi; 1513 interval_block = newi;
1447 interval_block_index = 0; 1514 interval_block_index = 0;
1448 } 1515 }
1449 val = &interval_block->intervals[interval_block_index++]; 1516 val = &interval_block->intervals[interval_block_index++];
1517 ASAN_UNPOISON_INTERVAL (val);
1450 } 1518 }
1451 1519
1452 MALLOC_UNBLOCK_INPUT; 1520 MALLOC_UNBLOCK_INPUT;
@@ -1687,6 +1755,41 @@ init_strings (void)
1687 staticpro (&empty_multibyte_string); 1755 staticpro (&empty_multibyte_string);
1688} 1756}
1689 1757
1758#if GC_ASAN_POISON_OBJECTS
1759/* Prepare s for denoting a free sdata struct, i.e, poison all bytes
1760 in the flexible array member, except the first SDATA_OFFSET bytes.
1761 This is only effective for strings of size n where n > sdata_size(n).
1762 */
1763# define ASAN_PREPARE_DEAD_SDATA(s, size) \
1764 do { \
1765 __asan_poison_memory_region ((s), sdata_size ((size))); \
1766 __asan_unpoison_memory_region (&(((s))->string), \
1767 sizeof (struct Lisp_String *)); \
1768 __asan_unpoison_memory_region (&SDATA_NBYTES ((s)), \
1769 sizeof (SDATA_NBYTES ((s)))); \
1770 } while (false)
1771/* Prepare s for storing string data for NBYTES bytes. */
1772# define ASAN_PREPARE_LIVE_SDATA(s, nbytes) \
1773 __asan_unpoison_memory_region ((s), sdata_size ((nbytes)))
1774# define ASAN_POISON_SBLOCK_DATA(b, size) \
1775 __asan_poison_memory_region ((b)->data, (size))
1776# define ASAN_POISON_STRING_BLOCK(b) \
1777 __asan_poison_memory_region ((b)->strings, STRING_BLOCK_SIZE)
1778# define ASAN_UNPOISON_STRING_BLOCK(b) \
1779 __asan_unpoison_memory_region ((b)->strings, STRING_BLOCK_SIZE)
1780# define ASAN_POISON_STRING(s) \
1781 __asan_poison_memory_region ((s), sizeof (*(s)))
1782# define ASAN_UNPOISON_STRING(s) \
1783 __asan_unpoison_memory_region ((s), sizeof (*(s)))
1784#else
1785# define ASAN_PREPARE_DEAD_SDATA(s, size) ((void) 0)
1786# define ASAN_PREPARE_LIVE_SDATA(s, nbytes) ((void) 0)
1787# define ASAN_POISON_SBLOCK_DATA(b, size) ((void) 0)
1788# define ASAN_POISON_STRING_BLOCK(b) ((void) 0)
1789# define ASAN_UNPOISON_STRING_BLOCK(b) ((void) 0)
1790# define ASAN_POISON_STRING(s) ((void) 0)
1791# define ASAN_UNPOISON_STRING(s) ((void) 0)
1792#endif
1690 1793
1691#ifdef GC_CHECK_STRING_BYTES 1794#ifdef GC_CHECK_STRING_BYTES
1692 1795
@@ -1805,12 +1908,14 @@ allocate_string (void)
1805 NEXT_FREE_LISP_STRING (s) = string_free_list; 1908 NEXT_FREE_LISP_STRING (s) = string_free_list;
1806 string_free_list = s; 1909 string_free_list = s;
1807 } 1910 }
1911 ASAN_POISON_STRING_BLOCK (b);
1808 } 1912 }
1809 1913
1810 check_string_free_list (); 1914 check_string_free_list ();
1811 1915
1812 /* Pop a Lisp_String off the free-list. */ 1916 /* Pop a Lisp_String off the free-list. */
1813 s = string_free_list; 1917 s = string_free_list;
1918 ASAN_UNPOISON_STRING (s);
1814 string_free_list = NEXT_FREE_LISP_STRING (s); 1919 string_free_list = NEXT_FREE_LISP_STRING (s);
1815 1920
1816 MALLOC_UNBLOCK_INPUT; 1921 MALLOC_UNBLOCK_INPUT;
@@ -1870,6 +1975,7 @@ allocate_string_data (struct Lisp_String *s,
1870#endif 1975#endif
1871 1976
1872 b = lisp_malloc (size + GC_STRING_EXTRA, clearit, MEM_TYPE_NON_LISP); 1977 b = lisp_malloc (size + GC_STRING_EXTRA, clearit, MEM_TYPE_NON_LISP);
1978 ASAN_POISON_SBLOCK_DATA (b, size);
1873 1979
1874#ifdef DOUG_LEA_MALLOC 1980#ifdef DOUG_LEA_MALLOC
1875 if (!mmap_lisp_allowed_p ()) 1981 if (!mmap_lisp_allowed_p ())
@@ -1891,6 +1997,8 @@ allocate_string_data (struct Lisp_String *s,
1891 { 1997 {
1892 /* Not enough room in the current sblock. */ 1998 /* Not enough room in the current sblock. */
1893 b = lisp_malloc (SBLOCK_SIZE, false, MEM_TYPE_NON_LISP); 1999 b = lisp_malloc (SBLOCK_SIZE, false, MEM_TYPE_NON_LISP);
2000 ASAN_POISON_SBLOCK_DATA (b, SBLOCK_SIZE);
2001
1894 data = b->data; 2002 data = b->data;
1895 b->next = NULL; 2003 b->next = NULL;
1896 b->next_free = data; 2004 b->next_free = data;
@@ -1903,10 +2011,19 @@ allocate_string_data (struct Lisp_String *s,
1903 } 2011 }
1904 2012
1905 data = b->next_free; 2013 data = b->next_free;
2014
1906 if (clearit) 2015 if (clearit)
1907 memset (SDATA_DATA (data), 0, nbytes); 2016 {
2017#if GC_ASAN_POISON_OBJECTS
2018 /* We are accessing SDATA_DATA (data) before it gets
2019 * normally unpoisoned, so do it manually. */
2020 __asan_unpoison_memory_region (SDATA_DATA (data), nbytes);
2021#endif
2022 memset (SDATA_DATA (data), 0, nbytes);
2023 }
1908 } 2024 }
1909 2025
2026 ASAN_PREPARE_LIVE_SDATA (data, nbytes);
1910 data->string = s; 2027 data->string = s;
1911 b->next_free = (sdata *) ((char *) data + needed + GC_STRING_EXTRA); 2028 b->next_free = (sdata *) ((char *) data + needed + GC_STRING_EXTRA);
1912 eassert ((uintptr_t) b->next_free % alignof (sdata) == 0); 2029 eassert ((uintptr_t) b->next_free % alignof (sdata) == 0);
@@ -1998,12 +2115,16 @@ sweep_strings (void)
1998 int i, nfree = 0; 2115 int i, nfree = 0;
1999 struct Lisp_String *free_list_before = string_free_list; 2116 struct Lisp_String *free_list_before = string_free_list;
2000 2117
2118 ASAN_UNPOISON_STRING_BLOCK (b);
2119
2001 next = b->next; 2120 next = b->next;
2002 2121
2003 for (i = 0; i < STRING_BLOCK_SIZE; ++i) 2122 for (i = 0; i < STRING_BLOCK_SIZE; ++i)
2004 { 2123 {
2005 struct Lisp_String *s = b->strings + i; 2124 struct Lisp_String *s = b->strings + i;
2006 2125
2126 ASAN_UNPOISON_STRING (s);
2127
2007 if (s->u.s.data) 2128 if (s->u.s.data)
2008 { 2129 {
2009 /* String was not on free-list before. */ 2130 /* String was not on free-list before. */
@@ -2040,6 +2161,8 @@ sweep_strings (void)
2040 2161
2041 /* Put the string on the free-list. */ 2162 /* Put the string on the free-list. */
2042 NEXT_FREE_LISP_STRING (s) = string_free_list; 2163 NEXT_FREE_LISP_STRING (s) = string_free_list;
2164 ASAN_POISON_STRING (s);
2165 ASAN_PREPARE_DEAD_SDATA (data, SDATA_NBYTES (data));
2043 string_free_list = s; 2166 string_free_list = s;
2044 ++nfree; 2167 ++nfree;
2045 } 2168 }
@@ -2048,6 +2171,8 @@ sweep_strings (void)
2048 { 2171 {
2049 /* S was on the free-list before. Put it there again. */ 2172 /* S was on the free-list before. Put it there again. */
2050 NEXT_FREE_LISP_STRING (s) = string_free_list; 2173 NEXT_FREE_LISP_STRING (s) = string_free_list;
2174 ASAN_POISON_STRING (s);
2175
2051 string_free_list = s; 2176 string_free_list = s;
2052 ++nfree; 2177 ++nfree;
2053 } 2178 }
@@ -2174,6 +2299,7 @@ compact_small_strings (void)
2174 if (from != to) 2299 if (from != to)
2175 { 2300 {
2176 eassert (tb != b || to < from); 2301 eassert (tb != b || to < from);
2302 ASAN_PREPARE_LIVE_SDATA (to, nbytes);
2177 memmove (to, from, size + GC_STRING_EXTRA); 2303 memmove (to, from, size + GC_STRING_EXTRA);
2178 to->string->u.s.data = SDATA_DATA (to); 2304 to->string->u.s.data = SDATA_DATA (to);
2179 } 2305 }
@@ -2525,6 +2651,7 @@ pin_string (Lisp_Object string)
2525 memcpy (s->u.s.data, data, size); 2651 memcpy (s->u.s.data, data, size);
2526 old_sdata->string = NULL; 2652 old_sdata->string = NULL;
2527 SDATA_NBYTES (old_sdata) = size; 2653 SDATA_NBYTES (old_sdata) = size;
2654 ASAN_PREPARE_DEAD_SDATA (old_sdata, size);
2528 } 2655 }
2529 s->u.s.size_byte = -3; 2656 s->u.s.size_byte = -3;
2530} 2657}
@@ -2582,6 +2709,24 @@ struct float_block
2582#define XFLOAT_UNMARK(fptr) \ 2709#define XFLOAT_UNMARK(fptr) \
2583 UNSETMARKBIT (FLOAT_BLOCK (fptr), FLOAT_INDEX ((fptr))) 2710 UNSETMARKBIT (FLOAT_BLOCK (fptr), FLOAT_INDEX ((fptr)))
2584 2711
2712#if GC_ASAN_POISON_OBJECTS
2713# define ASAN_POISON_FLOAT_BLOCK(fblk) \
2714 __asan_poison_memory_region ((fblk)->floats, \
2715 sizeof ((fblk)->floats))
2716# define ASAN_UNPOISON_FLOAT_BLOCK(fblk) \
2717 __asan_unpoison_memory_region ((fblk)->floats, \
2718 sizeof ((fblk)->floats))
2719# define ASAN_POISON_FLOAT(p) \
2720 __asan_poison_memory_region ((p), sizeof (struct Lisp_Float))
2721# define ASAN_UNPOISON_FLOAT(p) \
2722 __asan_unpoison_memory_region ((p), sizeof (struct Lisp_Float))
2723#else
2724# define ASAN_POISON_FLOAT_BLOCK(fblk) ((void) 0)
2725# define ASAN_UNPOISON_FLOAT_BLOCK(fblk) ((void) 0)
2726# define ASAN_POISON_FLOAT(p) ((void) 0)
2727# define ASAN_UNPOISON_FLOAT(p) ((void) 0)
2728#endif
2729
2585/* Current float_block. */ 2730/* Current float_block. */
2586 2731
2587static struct float_block *float_block; 2732static struct float_block *float_block;
@@ -2606,6 +2751,7 @@ make_float (double float_value)
2606 if (float_free_list) 2751 if (float_free_list)
2607 { 2752 {
2608 XSETFLOAT (val, float_free_list); 2753 XSETFLOAT (val, float_free_list);
2754 ASAN_UNPOISON_FLOAT (float_free_list);
2609 float_free_list = float_free_list->u.chain; 2755 float_free_list = float_free_list->u.chain;
2610 } 2756 }
2611 else 2757 else
@@ -2616,9 +2762,11 @@ make_float (double float_value)
2616 = lisp_align_malloc (sizeof *new, MEM_TYPE_FLOAT); 2762 = lisp_align_malloc (sizeof *new, MEM_TYPE_FLOAT);
2617 new->next = float_block; 2763 new->next = float_block;
2618 memset (new->gcmarkbits, 0, sizeof new->gcmarkbits); 2764 memset (new->gcmarkbits, 0, sizeof new->gcmarkbits);
2765 ASAN_POISON_FLOAT_BLOCK (new);
2619 float_block = new; 2766 float_block = new;
2620 float_block_index = 0; 2767 float_block_index = 0;
2621 } 2768 }
2769 ASAN_UNPOISON_FLOAT (&float_block->floats[float_block_index]);
2622 XSETFLOAT (val, &float_block->floats[float_block_index]); 2770 XSETFLOAT (val, &float_block->floats[float_block_index]);
2623 float_block_index++; 2771 float_block_index++;
2624 } 2772 }
@@ -2690,6 +2838,19 @@ static int cons_block_index = CONS_BLOCK_SIZE;
2690 2838
2691static struct Lisp_Cons *cons_free_list; 2839static struct Lisp_Cons *cons_free_list;
2692 2840
2841#if GC_ASAN_POISON_OBJECTS
2842# define ASAN_POISON_CONS_BLOCK(b) \
2843 __asan_poison_memory_region ((b)->conses, sizeof ((b)->conses))
2844# define ASAN_POISON_CONS(p) \
2845 __asan_poison_memory_region ((p), sizeof (struct Lisp_Cons))
2846# define ASAN_UNPOISON_CONS(p) \
2847 __asan_unpoison_memory_region ((p), sizeof (struct Lisp_Cons))
2848#else
2849# define ASAN_POISON_CONS_BLOCK(b) ((void) 0)
2850# define ASAN_POISON_CONS(p) ((void) 0)
2851# define ASAN_UNPOISON_CONS(p) ((void) 0)
2852#endif
2853
2693/* Explicitly free a cons cell by putting it on the free-list. */ 2854/* Explicitly free a cons cell by putting it on the free-list. */
2694 2855
2695void 2856void
@@ -2700,6 +2861,7 @@ free_cons (struct Lisp_Cons *ptr)
2700 cons_free_list = ptr; 2861 cons_free_list = ptr;
2701 ptrdiff_t nbytes = sizeof *ptr; 2862 ptrdiff_t nbytes = sizeof *ptr;
2702 tally_consing (-nbytes); 2863 tally_consing (-nbytes);
2864 ASAN_POISON_CONS (ptr);
2703} 2865}
2704 2866
2705DEFUN ("cons", Fcons, Scons, 2, 2, 0, 2867DEFUN ("cons", Fcons, Scons, 2, 2, 0,
@@ -2712,6 +2874,7 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0,
2712 2874
2713 if (cons_free_list) 2875 if (cons_free_list)
2714 { 2876 {
2877 ASAN_UNPOISON_CONS (cons_free_list);
2715 XSETCONS (val, cons_free_list); 2878 XSETCONS (val, cons_free_list);
2716 cons_free_list = cons_free_list->u.s.u.chain; 2879 cons_free_list = cons_free_list->u.s.u.chain;
2717 } 2880 }
@@ -2722,10 +2885,12 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0,
2722 struct cons_block *new 2885 struct cons_block *new
2723 = lisp_align_malloc (sizeof *new, MEM_TYPE_CONS); 2886 = lisp_align_malloc (sizeof *new, MEM_TYPE_CONS);
2724 memset (new->gcmarkbits, 0, sizeof new->gcmarkbits); 2887 memset (new->gcmarkbits, 0, sizeof new->gcmarkbits);
2888 ASAN_POISON_CONS_BLOCK (new);
2725 new->next = cons_block; 2889 new->next = cons_block;
2726 cons_block = new; 2890 cons_block = new;
2727 cons_block_index = 0; 2891 cons_block_index = 0;
2728 } 2892 }
2893 ASAN_UNPOISON_CONS (&cons_block->conses[cons_block_index]);
2729 XSETCONS (val, &cons_block->conses[cons_block_index]); 2894 XSETCONS (val, &cons_block->conses[cons_block_index]);
2730 cons_block_index++; 2895 cons_block_index++;
2731 } 2896 }
@@ -2980,6 +3145,19 @@ static struct large_vector *large_vectors;
2980 3145
2981Lisp_Object zero_vector; 3146Lisp_Object zero_vector;
2982 3147
3148#if GC_ASAN_POISON_OBJECTS
3149# define ASAN_POISON_VECTOR_CONTENTS(v, bytes) \
3150 __asan_poison_memory_region ((v)->contents, (bytes))
3151# define ASAN_UNPOISON_VECTOR_CONTENTS(v, bytes) \
3152 __asan_unpoison_memory_region ((v)->contents, (bytes))
3153# define ASAN_UNPOISON_VECTOR_BLOCK(b) \
3154 __asan_unpoison_memory_region ((b)->data, sizeof ((b)->data))
3155#else
3156# define ASAN_POISON_VECTOR_CONTENTS(v, bytes) ((void) 0)
3157# define ASAN_UNPOISON_VECTOR_CONTENTS(v, bytes) ((void) 0)
3158# define ASAN_UNPOISON_VECTOR_BLOCK(b) ((void) 0)
3159#endif
3160
2983/* Common shortcut to setup vector on a free list. */ 3161/* Common shortcut to setup vector on a free list. */
2984 3162
2985static void 3163static void
@@ -2992,6 +3170,7 @@ setup_on_free_list (struct Lisp_Vector *v, ptrdiff_t nbytes)
2992 ptrdiff_t vindex = VINDEX (nbytes); 3170 ptrdiff_t vindex = VINDEX (nbytes);
2993 eassert (vindex < VECTOR_MAX_FREE_LIST_INDEX); 3171 eassert (vindex < VECTOR_MAX_FREE_LIST_INDEX);
2994 set_next_vector (v, vector_free_lists[vindex]); 3172 set_next_vector (v, vector_free_lists[vindex]);
3173 ASAN_POISON_VECTOR_CONTENTS (v, nbytes - header_size);
2995 vector_free_lists[vindex] = v; 3174 vector_free_lists[vindex] = v;
2996} 3175}
2997 3176
@@ -3039,6 +3218,7 @@ allocate_vector_from_block (ptrdiff_t nbytes)
3039 if (vector_free_lists[index]) 3218 if (vector_free_lists[index])
3040 { 3219 {
3041 vector = vector_free_lists[index]; 3220 vector = vector_free_lists[index];
3221 ASAN_UNPOISON_VECTOR_CONTENTS (vector, nbytes - header_size);
3042 vector_free_lists[index] = next_vector (vector); 3222 vector_free_lists[index] = next_vector (vector);
3043 return vector; 3223 return vector;
3044 } 3224 }
@@ -3052,12 +3232,18 @@ allocate_vector_from_block (ptrdiff_t nbytes)
3052 { 3232 {
3053 /* This vector is larger than requested. */ 3233 /* This vector is larger than requested. */
3054 vector = vector_free_lists[index]; 3234 vector = vector_free_lists[index];
3235 ASAN_UNPOISON_VECTOR_CONTENTS (vector, nbytes - header_size);
3055 vector_free_lists[index] = next_vector (vector); 3236 vector_free_lists[index] = next_vector (vector);
3056 3237
3057 /* Excess bytes are used for the smaller vector, 3238 /* Excess bytes are used for the smaller vector,
3058 which should be set on an appropriate free list. */ 3239 which should be set on an appropriate free list. */
3059 restbytes = index * roundup_size + VBLOCK_BYTES_MIN - nbytes; 3240 restbytes = index * roundup_size + VBLOCK_BYTES_MIN - nbytes;
3060 eassert (restbytes % roundup_size == 0); 3241 eassert (restbytes % roundup_size == 0);
3242#if GC_ASAN_POISON_OBJECTS
3243 /* Ensure that accessing excess bytes does not trigger ASan. */
3244 __asan_unpoison_memory_region (ADVANCE (vector, nbytes),
3245 restbytes);
3246#endif
3061 setup_on_free_list (ADVANCE (vector, nbytes), restbytes); 3247 setup_on_free_list (ADVANCE (vector, nbytes), restbytes);
3062 return vector; 3248 return vector;
3063 } 3249 }
@@ -3233,6 +3419,7 @@ sweep_vectors (void)
3233 for (vector = (struct Lisp_Vector *) block->data; 3419 for (vector = (struct Lisp_Vector *) block->data;
3234 VECTOR_IN_BLOCK (vector, block); vector = next) 3420 VECTOR_IN_BLOCK (vector, block); vector = next)
3235 { 3421 {
3422 ASAN_UNPOISON_VECTOR_BLOCK (block);
3236 if (XVECTOR_MARKED_P (vector)) 3423 if (XVECTOR_MARKED_P (vector))
3237 { 3424 {
3238 XUNMARK_VECTOR (vector); 3425 XUNMARK_VECTOR (vector);
@@ -3608,6 +3795,23 @@ struct symbol_block
3608 struct symbol_block *next; 3795 struct symbol_block *next;
3609}; 3796};
3610 3797
3798#if GC_ASAN_POISON_OBJECTS
3799# define ASAN_POISON_SYMBOL_BLOCK(s) \
3800 __asan_poison_memory_region ((s)->symbols, sizeof ((s)->symbols))
3801# define ASAN_UNPOISON_SYMBOL_BLOCK(s) \
3802 __asan_unpoison_memory_region ((s)->symbols, sizeof ((s)->symbols))
3803# define ASAN_POISON_SYMBOL(sym) \
3804 __asan_poison_memory_region ((sym), sizeof (*(sym)))
3805# define ASAN_UNPOISON_SYMBOL(sym) \
3806 __asan_unpoison_memory_region ((sym), sizeof (*(sym)))
3807
3808#else
3809# define ASAN_POISON_SYMBOL_BLOCK(s) ((void) 0)
3810# define ASAN_UNPOISON_SYMBOL_BLOCK(s) ((void) 0)
3811# define ASAN_POISON_SYMBOL(sym) ((void) 0)
3812# define ASAN_UNPOISON_SYMBOL(sym) ((void) 0)
3813#endif
3814
3611/* Current symbol block and index of first unused Lisp_Symbol 3815/* Current symbol block and index of first unused Lisp_Symbol
3612 structure in it. */ 3816 structure in it. */
3613 3817
@@ -3661,6 +3865,7 @@ Its value is void, and its function definition and property list are nil. */)
3661 3865
3662 if (symbol_free_list) 3866 if (symbol_free_list)
3663 { 3867 {
3868 ASAN_UNPOISON_SYMBOL (symbol_free_list);
3664 XSETSYMBOL (val, symbol_free_list); 3869 XSETSYMBOL (val, symbol_free_list);
3665 symbol_free_list = symbol_free_list->u.s.next; 3870 symbol_free_list = symbol_free_list->u.s.next;
3666 } 3871 }
@@ -3670,10 +3875,13 @@ Its value is void, and its function definition and property list are nil. */)
3670 { 3875 {
3671 struct symbol_block *new 3876 struct symbol_block *new
3672 = lisp_malloc (sizeof *new, false, MEM_TYPE_SYMBOL); 3877 = lisp_malloc (sizeof *new, false, MEM_TYPE_SYMBOL);
3878 ASAN_POISON_SYMBOL_BLOCK (new);
3673 new->next = symbol_block; 3879 new->next = symbol_block;
3674 symbol_block = new; 3880 symbol_block = new;
3675 symbol_block_index = 0; 3881 symbol_block_index = 0;
3676 } 3882 }
3883
3884 ASAN_UNPOISON_SYMBOL (&symbol_block->symbols[symbol_block_index]);
3677 XSETSYMBOL (val, &symbol_block->symbols[symbol_block_index]); 3885 XSETSYMBOL (val, &symbol_block->symbols[symbol_block_index]);
3678 symbol_block_index++; 3886 symbol_block_index++;
3679 } 3887 }
@@ -4561,6 +4769,11 @@ static struct Lisp_String *
4561live_string_holding (struct mem_node *m, void *p) 4769live_string_holding (struct mem_node *m, void *p)
4562{ 4770{
4563 eassert (m->type == MEM_TYPE_STRING); 4771 eassert (m->type == MEM_TYPE_STRING);
4772#if GC_ASAN_POISON_OBJECTS
4773 if (__asan_address_is_poisoned (p))
4774 return NULL;
4775#endif
4776
4564 struct string_block *b = m->start; 4777 struct string_block *b = m->start;
4565 char *cp = p; 4778 char *cp = p;
4566 ptrdiff_t offset = cp - (char *) &b->strings[0]; 4779 ptrdiff_t offset = cp - (char *) &b->strings[0];
@@ -4577,6 +4790,10 @@ live_string_holding (struct mem_node *m, void *p)
4577 || off == offsetof (struct Lisp_String, u.s.data)) 4790 || off == offsetof (struct Lisp_String, u.s.data))
4578 { 4791 {
4579 struct Lisp_String *s = p = cp -= off; 4792 struct Lisp_String *s = p = cp -= off;
4793#if GC_ASAN_POISON_OBJECTS
4794 if (__asan_region_is_poisoned (s, sizeof (*s)))
4795 return NULL;
4796#endif
4580 if (s->u.s.data) 4797 if (s->u.s.data)
4581 return s; 4798 return s;
4582 } 4799 }
@@ -4598,6 +4815,11 @@ static struct Lisp_Cons *
4598live_cons_holding (struct mem_node *m, void *p) 4815live_cons_holding (struct mem_node *m, void *p)
4599{ 4816{
4600 eassert (m->type == MEM_TYPE_CONS); 4817 eassert (m->type == MEM_TYPE_CONS);
4818#if GC_ASAN_POISON_OBJECTS
4819 if (__asan_address_is_poisoned (p))
4820 return NULL;
4821#endif
4822
4601 struct cons_block *b = m->start; 4823 struct cons_block *b = m->start;
4602 char *cp = p; 4824 char *cp = p;
4603 ptrdiff_t offset = cp - (char *) &b->conses[0]; 4825 ptrdiff_t offset = cp - (char *) &b->conses[0];
@@ -4615,6 +4837,10 @@ live_cons_holding (struct mem_node *m, void *p)
4615 || off == offsetof (struct Lisp_Cons, u.s.u.cdr)) 4837 || off == offsetof (struct Lisp_Cons, u.s.u.cdr))
4616 { 4838 {
4617 struct Lisp_Cons *s = p = cp -= off; 4839 struct Lisp_Cons *s = p = cp -= off;
4840#if GC_ASAN_POISON_OBJECTS
4841 if (__asan_region_is_poisoned (s, sizeof (*s)))
4842 return NULL;
4843#endif
4618 if (!deadp (s->u.s.car)) 4844 if (!deadp (s->u.s.car))
4619 return s; 4845 return s;
4620 } 4846 }
@@ -4637,6 +4863,10 @@ static struct Lisp_Symbol *
4637live_symbol_holding (struct mem_node *m, void *p) 4863live_symbol_holding (struct mem_node *m, void *p)
4638{ 4864{
4639 eassert (m->type == MEM_TYPE_SYMBOL); 4865 eassert (m->type == MEM_TYPE_SYMBOL);
4866#if GC_ASAN_POISON_OBJECTS
4867 if (__asan_address_is_poisoned (p))
4868 return NULL;
4869#endif
4640 struct symbol_block *b = m->start; 4870 struct symbol_block *b = m->start;
4641 char *cp = p; 4871 char *cp = p;
4642 ptrdiff_t offset = cp - (char *) &b->symbols[0]; 4872 ptrdiff_t offset = cp - (char *) &b->symbols[0];
@@ -4662,6 +4892,10 @@ live_symbol_holding (struct mem_node *m, void *p)
4662 || off == offsetof (struct Lisp_Symbol, u.s.next)) 4892 || off == offsetof (struct Lisp_Symbol, u.s.next))
4663 { 4893 {
4664 struct Lisp_Symbol *s = p = cp -= off; 4894 struct Lisp_Symbol *s = p = cp -= off;
4895#if GC_ASAN_POISON_OBJECTS
4896 if (__asan_region_is_poisoned (s, sizeof (*s)))
4897 return NULL;
4898#endif
4665 if (!deadp (s->u.s.function)) 4899 if (!deadp (s->u.s.function))
4666 return s; 4900 return s;
4667 } 4901 }
@@ -4684,6 +4918,11 @@ static struct Lisp_Float *
4684live_float_holding (struct mem_node *m, void *p) 4918live_float_holding (struct mem_node *m, void *p)
4685{ 4919{
4686 eassert (m->type == MEM_TYPE_FLOAT); 4920 eassert (m->type == MEM_TYPE_FLOAT);
4921#if GC_ASAN_POISON_OBJECTS
4922 if (__asan_address_is_poisoned (p))
4923 return NULL;
4924#endif
4925
4687 struct float_block *b = m->start; 4926 struct float_block *b = m->start;
4688 char *cp = p; 4927 char *cp = p;
4689 ptrdiff_t offset = cp - (char *) &b->floats[0]; 4928 ptrdiff_t offset = cp - (char *) &b->floats[0];
@@ -4698,8 +4937,12 @@ live_float_holding (struct mem_node *m, void *p)
4698 && (b != float_block 4937 && (b != float_block
4699 || offset / sizeof b->floats[0] < float_block_index)) 4938 || offset / sizeof b->floats[0] < float_block_index))
4700 { 4939 {
4701 p = cp - off; 4940 struct Lisp_Float *f = (struct Lisp_Float *) (cp - off);
4702 return p; 4941#if GC_ASAN_POISON_OBJECTS
4942 if (__asan_region_is_poisoned (f, sizeof (*f)))
4943 return NULL;
4944#endif
4945 return f;
4703 } 4946 }
4704 } 4947 }
4705 return NULL; 4948 return NULL;
@@ -7181,11 +7424,13 @@ sweep_conses (void)
7181 struct Lisp_Cons *acons = &cblk->conses[pos]; 7424 struct Lisp_Cons *acons = &cblk->conses[pos];
7182 if (!XCONS_MARKED_P (acons)) 7425 if (!XCONS_MARKED_P (acons))
7183 { 7426 {
7427 ASAN_UNPOISON_CONS (&cblk->conses[pos]);
7184 this_free++; 7428 this_free++;
7185 cblk->conses[pos].u.s.u.chain = cons_free_list; 7429 cblk->conses[pos].u.s.u.chain = cons_free_list;
7186 cons_free_list = &cblk->conses[pos]; 7430 cons_free_list = &cblk->conses[pos];
7187 cons_free_list->u.s.car = dead_object (); 7431 cons_free_list->u.s.car = dead_object ();
7188 } 7432 ASAN_POISON_CONS (&cblk->conses[pos]);
7433 }
7189 else 7434 else
7190 { 7435 {
7191 num_used++; 7436 num_used++;
@@ -7203,6 +7448,7 @@ sweep_conses (void)
7203 { 7448 {
7204 *cprev = cblk->next; 7449 *cprev = cblk->next;
7205 /* Unhook from the free list. */ 7450 /* Unhook from the free list. */
7451 ASAN_UNPOISON_CONS (&cblk->conses[0]);
7206 cons_free_list = cblk->conses[0].u.s.u.chain; 7452 cons_free_list = cblk->conses[0].u.s.u.chain;
7207 lisp_align_free (cblk); 7453 lisp_align_free (cblk);
7208 } 7454 }
@@ -7229,6 +7475,7 @@ sweep_floats (void)
7229 for (struct float_block *fblk; (fblk = *fprev); ) 7475 for (struct float_block *fblk; (fblk = *fprev); )
7230 { 7476 {
7231 int this_free = 0; 7477 int this_free = 0;
7478 ASAN_UNPOISON_FLOAT_BLOCK (fblk);
7232 for (int i = 0; i < lim; i++) 7479 for (int i = 0; i < lim; i++)
7233 { 7480 {
7234 struct Lisp_Float *afloat = &fblk->floats[i]; 7481 struct Lisp_Float *afloat = &fblk->floats[i];
@@ -7236,6 +7483,7 @@ sweep_floats (void)
7236 { 7483 {
7237 this_free++; 7484 this_free++;
7238 fblk->floats[i].u.chain = float_free_list; 7485 fblk->floats[i].u.chain = float_free_list;
7486 ASAN_POISON_FLOAT (&fblk->floats[i]);
7239 float_free_list = &fblk->floats[i]; 7487 float_free_list = &fblk->floats[i];
7240 } 7488 }
7241 else 7489 else
@@ -7252,7 +7500,8 @@ sweep_floats (void)
7252 { 7500 {
7253 *fprev = fblk->next; 7501 *fprev = fblk->next;
7254 /* Unhook from the free list. */ 7502 /* Unhook from the free list. */
7255 float_free_list = fblk->floats[0].u.chain; 7503 ASAN_UNPOISON_FLOAT (&fblk->floats[0]);
7504 float_free_list = fblk->floats[0].u.chain;
7256 lisp_align_free (fblk); 7505 lisp_align_free (fblk);
7257 } 7506 }
7258 else 7507 else
@@ -7278,13 +7527,14 @@ sweep_intervals (void)
7278 for (struct interval_block *iblk; (iblk = *iprev); ) 7527 for (struct interval_block *iblk; (iblk = *iprev); )
7279 { 7528 {
7280 int this_free = 0; 7529 int this_free = 0;
7281 7530 ASAN_UNPOISON_INTERVAL_BLOCK (iblk);
7282 for (int i = 0; i < lim; i++) 7531 for (int i = 0; i < lim; i++)
7283 { 7532 {
7284 if (!iblk->intervals[i].gcmarkbit) 7533 if (!iblk->intervals[i].gcmarkbit)
7285 { 7534 {
7286 set_interval_parent (&iblk->intervals[i], interval_free_list); 7535 set_interval_parent (&iblk->intervals[i], interval_free_list);
7287 interval_free_list = &iblk->intervals[i]; 7536 interval_free_list = &iblk->intervals[i];
7537 ASAN_POISON_INTERVAL (&iblk->intervals[i]);
7288 this_free++; 7538 this_free++;
7289 } 7539 }
7290 else 7540 else
@@ -7301,6 +7551,7 @@ sweep_intervals (void)
7301 { 7551 {
7302 *iprev = iblk->next; 7552 *iprev = iblk->next;
7303 /* Unhook from the free list. */ 7553 /* Unhook from the free list. */
7554 ASAN_UNPOISON_INTERVAL (&iblk->intervals[0]);
7304 interval_free_list = INTERVAL_PARENT (&iblk->intervals[0]); 7555 interval_free_list = INTERVAL_PARENT (&iblk->intervals[0]);
7305 lisp_free (iblk); 7556 lisp_free (iblk);
7306 } 7557 }
@@ -7330,6 +7581,8 @@ sweep_symbols (void)
7330 7581
7331 for (sblk = symbol_block; sblk; sblk = *sprev) 7582 for (sblk = symbol_block; sblk; sblk = *sprev)
7332 { 7583 {
7584 ASAN_UNPOISON_SYMBOL_BLOCK (sblk);
7585
7333 int this_free = 0; 7586 int this_free = 0;
7334 struct Lisp_Symbol *sym = sblk->symbols; 7587 struct Lisp_Symbol *sym = sblk->symbols;
7335 struct Lisp_Symbol *end = sym + lim; 7588 struct Lisp_Symbol *end = sym + lim;
@@ -7351,7 +7604,8 @@ sweep_symbols (void)
7351 sym->u.s.next = symbol_free_list; 7604 sym->u.s.next = symbol_free_list;
7352 symbol_free_list = sym; 7605 symbol_free_list = sym;
7353 symbol_free_list->u.s.function = dead_object (); 7606 symbol_free_list->u.s.function = dead_object ();
7354 ++this_free; 7607 ASAN_POISON_SYMBOL (sym);
7608 ++this_free;
7355 } 7609 }
7356 else 7610 else
7357 { 7611 {
@@ -7370,6 +7624,7 @@ sweep_symbols (void)
7370 { 7624 {
7371 *sprev = sblk->next; 7625 *sprev = sblk->next;
7372 /* Unhook from the free list. */ 7626 /* Unhook from the free list. */
7627 ASAN_UNPOISON_SYMBOL (&sblk->symbols[0]);
7373 symbol_free_list = sblk->symbols[0].u.s.next; 7628 symbol_free_list = sblk->symbols[0].u.s.next;
7374 lisp_free (sblk); 7629 lisp_free (sblk);
7375 } 7630 }