From 4fb3dbc7b396d1a4cad2fd8ff23d2b226218f50b Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 1 Jan 2025 16:17:58 -0800 Subject: [PATCH] parser: improve unreachable state removal Currently states are added to the reachable set when they are popped from the workqueue. This however can result in states being added to the work queue multiple times and reprocessed. Eg. If state 2 has the transitions, and 9 is not in the reachable set a -> 9 b -> 9 c -> 9 d -> 9 e -> 3 then 9 will get pushed onto the work 4 times. Even worse other states on the workqueue may also add state 9 to the workqueue because it has not been added to the reachable set. Instead add states to the reachable set when they are added to the workqueue. The first encounter with a state will result in it being reachable and all other encounters will see that it already in the set and not add it to the workqueue. Signed-off-by: John Johansen --- parser/libapparmor_re/hfa.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index 575d72073..93d4d3480 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -546,6 +546,14 @@ void DFA::dump_uniq_perms(const char *s) //TODO: add prompt } +// make sure work_queue and reachable insertion are always done together +static void push_reachable(set &reachable, list &work_queue, + State *state) +{ + work_queue.push_back(state); + reachable.insert(state); +} + /* Remove dead or unreachable states */ void DFA::remove_unreachable(optflags const &opts) { @@ -553,19 +561,18 @@ void DFA::remove_unreachable(optflags const &opts) /* find the set of reachable states */ reachable.insert(nonmatching); - work_queue.push_back(start); + push_reachable(reachable, work_queue, start); while (!work_queue.empty()) { State *from = work_queue.front(); work_queue.pop_front(); - reachable.insert(from); if (from->otherwise != nonmatching && reachable.find(from->otherwise) == reachable.end()) - work_queue.push_back(from->otherwise); + push_reachable(reachable, work_queue, from->otherwise); for (StateTrans::iterator j = from->trans.begin(); j != from->trans.end(); j++) { if (reachable.find(j->second) == reachable.end()) - work_queue.push_back(j->second); + push_reachable(reachable, work_queue, j->second); } }