diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2021-04-06 20:06:18 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2021-04-06 20:06:18 -0700 |
commit | 174182a29c785493ed41231caff36f35c56819cf (patch) | |
tree | ebe0f5d3f1d26a5fbc360a8c064d07990e4d257e /regex.h | |
parent | 695bd0d14d03e2b3380d2913b87dadc60383235f (diff) | |
download | txr-174182a29c785493ed41231caff36f35c56819cf.tar.gz txr-174182a29c785493ed41231caff36f35c56819cf.tar.bz2 txr-174182a29c785493ed41231caff36f35c56819cf.zip |
gc: fix astonishing bug in weak hash processing.
This is a flaw that has been in the code since the initial
implementation in 2009. Weak hash tables are only partially
marked during the initial garbage collection marking phase.
They are put into a global list, which is then walked again
to do the weak processing: to expire items which are not
reachable, and then finish walking the table objects. Problem
is, the code assumes that this late processing will not
discover more hash tables and put them into that global list.
This creates a problem when weak hash table contain weak
hash tables, such as in the important and very common case
when a global variable (binding stored in a weak hash table)
contains a weak hash table! These hash tables discovered
during weak hash table processing are partially marked, and
left that way. The result is that their table vectors get
prematurely scavenged by the garbage collector, and then
fall victim to use-after-free crashing.
Note: do_iters doesn't have this bug. Though the
reachable_iters list resembles reachable_weak_hashes, the key
difference is that do_iters does not do any marking, and
so will not discover any more reachable objects.
All it does is update some counts in the hashes to which
the still-reachable iterators point.
* hash.c (do_weak_tables): Clear the reachable_weak_hashes
list on entry into the function, taking a local copy of its
head. After walking the list, check the global variable again;
it if has become non-null, it means more weak tables were
discovered and added to the list. In that case, make a
recursive call (susceptible to tail call treatment) to process
the list again.
Diffstat (limited to 'regex.h')
0 files changed, 0 insertions, 0 deletions