summaryrefslogtreecommitdiffstats
path: root/glob.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-12-17 19:26:54 -0800
committerKaz Kylheku <kaz@kylheku.com>2021-12-17 19:26:54 -0800
commita937384ebf3e387c81897189e42c87a574b937fb (patch)
treeb64aebc615af324ba086f5d189fbde29973ba715 /glob.c
parentf56d0211640a4cae6181bb7e7aac8aacfa2f6ab5 (diff)
downloadtxr-a937384ebf3e387c81897189e42c87a574b937fb.tar.gz
txr-a937384ebf3e387c81897189e42c87a574b937fb.tar.bz2
txr-a937384ebf3e387c81897189e42c87a574b937fb.zip
iter-begin: gc problem.
Issue 1: the seq_iter_init_with_info function potentially allocates an object via hash_begin or tree_begin and installs it into the iterator. The problem is that under iter_begin, the iterator is a heaped object; this extra allocation can trigger gc which pushes the iterator into the mature generation; yet the assignment in seq_iter_init_with_info is just a plain assignment without using the set macro. Issue 2: when gc is triggered in the above situations, it crashes due to the struct seq_iter being incompletely initialized. The mark function tries to dereference the si->ops pointer. Alas, this is initialized in the wrong order inside seq_iter_init_with_info. Concretely, tree_begin is called first, and then the it->ops = &si_tree_ops assignment is performed, which means that if the garbage collector runs under tree_begin, it sees a null it->ops pointer. However, this issue cannot just be fixed here by rearranging the code because that leaves Issue 1 unsolved. Also, this initialization order is not an issue for stack-allocated struct seq_iters. The fix for Issue 1 and Issue 2 is to reorder things in iter_begin. Initialize the iterator structure first, and then create the iterator cobj. Now, of course, that goes against the usual correct protocol for object initialization. If we just do this re-ordering naively, we have Issue 3: the familiar problem that the cobj() call triggers gc, and the iterator object (e.g. from tree_iter) that has been stored into the seq_iter structure is not visible ot the GC, and is reclaimed. * lib.c (iter_begin): reorder the calls so that seq_iter_init_with_info is called first, and then the cobj to create from it the heap-allocated iterator, taking care of Issue 1 and Issue 2. To avoid Issue 3, after initializing the structure, we pull out the vulnerable iterator object into a local variable, and pass it to gc_hint(), to ensure that the variable is spilled into the stack, thereby protecting it from reclamation. (seq_begin): This function has exactly the same issue, fixed in the same way.
Diffstat (limited to 'glob.c')
0 files changed, 0 insertions, 0 deletions