summaryrefslogtreecommitdiffstats
path: root/opt.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2020-03-23 12:59:56 -0400
committerTavian Barnes <tavianator@tavianator.com>2020-03-23 12:59:56 -0400
commit12e93e7c7721f9a581f62a8df9534571d0ec353d (patch)
tree4b352f5a4c940438fb9bcca117a1d330f6134d93 /opt.c
parentcd76a94a328719df61c15b02f25f984b43cce19e (diff)
downloadbfs-12e93e7c7721f9a581f62a8df9534571d0ec353d.tar.xz
opt: Avoid dangling pointers in de_morgan()
If optimize_{and,or}_expr() relocates expr, we need to update the parent expr or else we might return garbage. It seems impossible to actually trigger this bug right now, since the {and,or} optimizations are symmetric, but it could be hit if the simplifications in de_morgan() expose more information than was known previously.
Diffstat (limited to 'opt.c')
-rw-r--r--opt.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/opt.c b/opt.c
index 019a136..57f5dbf 100644
--- a/opt.c
+++ b/opt.c
@@ -308,11 +308,11 @@ static struct expr *de_morgan(const struct opt_state *state, struct expr *expr,
has_parent = false;
}
+ assert(expr->eval == eval_and || expr->eval == eval_or);
if (expr->eval == eval_and) {
expr->eval = eval_or;
expr->argv = &fake_or_arg;
} else {
- assert(expr->eval == eval_or);
expr->eval = eval_and;
expr->argv = &fake_and_arg;
}
@@ -342,11 +342,13 @@ static struct expr *de_morgan(const struct opt_state *state, struct expr *expr,
} else {
expr = optimize_or_expr(state, expr);
}
+ if (has_parent) {
+ parent->rhs = expr;
+ } else {
+ parent = expr;
+ }
if (!expr) {
- if (has_parent) {
- parent->rhs = NULL;
- free_expr(parent);
- }
+ free_expr(parent);
return NULL;
}