summaryrefslogtreecommitdiffstats
path: root/regex.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2018-04-04 23:04:16 -0700
committerKaz Kylheku <kaz@kylheku.com>2018-04-04 23:04:16 -0700
commita9af2631068edfcb26b1823cf63b078ddf75dd79 (patch)
tree2f70b2c0e370d161e05e5a04dd053e9e61245be0 /regex.c
parent0cb57f957f6ea07a8e33173d39716716db455d30 (diff)
downloadtxr-a9af2631068edfcb26b1823cf63b078ddf75dd79.tar.gz
txr-a9af2631068edfcb26b1823cf63b078ddf75dd79.tar.bz2
txr-a9af2631068edfcb26b1823cf63b078ddf75dd79.zip
regex: fix double free corruption bug.
Unfortunately, the nfa_state_free function doesn't check the static flag on a character set and just calls chr_set_destroy. So when one of the static character sets is planted into the NFA graph, when that graph is garbage-collected, it blows away the static character set. Then when that happens twice for the same set, boom! We make an alteration to make the destruction more defensive. Callers of char_set_destroy are no longer saddled with the responsibility of honoring the static flag buried in the object. Instead, that function itself check the static flag. An argument is provided to force the deletion in spite of the static flag; that is needed for the global cleanup of the static states. (Only occurs if txr is run with --free-all and cleanly exited.) * regex.c (char_set_destroy): Take extra argument, force. If the set is marked static, then do nothing, unless force is nonzero. (char_set_cobj_destroy): Don't check the static flag, just call char_set_destroy, force zero. (nfa_state_free): Add force zero argument to char_set_destroy call. The double free bug is thereby fixed here; static sets are protected. (regex_free_all): Force all the char_set_destroy calls here.
Diffstat (limited to 'regex.c')
-rw-r--r--regex.c24
1 files changed, 13 insertions, 11 deletions
diff --git a/regex.c b/regex.c
index 3fb6b42c..9e413204 100644
--- a/regex.c
+++ b/regex.c
@@ -547,11 +547,14 @@ static char_set_t *char_set_create(chset_type_t type, wchar_t base, unsigned st)
return cs;
}
-static void char_set_destroy(char_set_t *set)
+static void char_set_destroy(char_set_t *set, int force)
{
if (!set)
return;
+ if (set->any.stat && !force)
+ return;
+
switch (set->any.type) {
case CHSET_DISPLACED:
case CHSET_SMALL:
@@ -799,8 +802,7 @@ static void init_special_char_sets(void)
static void char_set_cobj_destroy(val chset)
{
char_set_t *set = coerce(char_set_t *, chset->co.handle);
- if (!set->any.stat)
- char_set_destroy(set);
+ char_set_destroy(set, 0);
chset->co.handle = 0;
}
@@ -852,7 +854,7 @@ static nfa_state_t *nfa_state_wild(nfa_state_t *t)
static void nfa_state_free(nfa_state_t *st)
{
if (st->a.kind == nfa_set)
- char_set_destroy(st->s.set);
+ char_set_destroy(st->s.set, 0);
free(st);
}
@@ -3303,11 +3305,11 @@ void regex_init(void)
void regex_free_all(void)
{
- char_set_destroy(space_cs);
- char_set_destroy(digit_cs);
- char_set_destroy(word_cs);
- char_set_destroy(cspace_cs);
- char_set_destroy(cdigit_cs);
- char_set_destroy(cword_cs);
- char_set_destroy(wide_cs);
+ char_set_destroy(space_cs, 1);
+ char_set_destroy(digit_cs, 1);
+ char_set_destroy(word_cs, 1);
+ char_set_destroy(cspace_cs, 1);
+ char_set_destroy(cdigit_cs, 1);
+ char_set_destroy(cword_cs, 1);
+ char_set_destroy(wide_cs, 1);
}