When disabling optionals, the AST needs to be reset only if one of the optional blocks being disabled contains a declaration. Call the function cil_tree_subtree_has_decl() for each optional block being disabled and only reset the AST if one of them has a declaration in it. Signed-off-by: James Carter <jwcart2@xxxxxxxxx> --- libsepol/cil/src/cil_resolve_ast.c | 58 +++++++++++++++++------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c index 5245cc15..0ea5b169 100644 --- a/libsepol/cil/src/cil_resolve_ast.c +++ b/libsepol/cil/src/cil_resolve_ast.c @@ -4230,33 +4230,43 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current) if (changed) { struct cil_list_item *item; if (pass > CIL_PASS_CALL1) { - /* Need to re-resolve because an optional was disabled that contained - * one or more declarations. We only need to reset to the call1 pass - * because things done in the preceding passes aren't allowed in - * optionals, and thus can't be disabled. - * Note: set pass to CIL_PASS_CALL1 because the pass++ will increment - * it to CIL_PASS_CALL2 - */ - cil_log(CIL_INFO, "Resetting declarations\n"); - - if (pass >= CIL_PASS_MISC1) { - __cil_ordered_lists_reset(&extra_args.sidorder_lists); - __cil_ordered_lists_reset(&extra_args.classorder_lists); - __cil_ordered_lists_reset(&extra_args.unordered_classorder_lists); - __cil_ordered_lists_reset(&extra_args.catorder_lists); - __cil_ordered_lists_reset(&extra_args.sensitivityorder_lists); - cil_list_destroy(&db->sidorder, CIL_FALSE); - cil_list_destroy(&db->classorder, CIL_FALSE); - cil_list_destroy(&db->catorder, CIL_FALSE); - cil_list_destroy(&db->sensitivityorder, CIL_FALSE); + int has_decls = CIL_FALSE; + + cil_list_for_each(item, extra_args.to_destroy) { + has_decls = cil_tree_subtree_has_decl(item->data); + if (has_decls) { + break; + } } - pass = CIL_PASS_CALL1; + if (has_decls) { + /* Need to re-resolve because an optional was disabled that + * contained one or more declarations. + * Everything that needs to be reset comes after the + * CIL_PASS_CALL2 pass. We set pass to CIL_PASS_CALL1 because + * the pass++ will increment it to CIL_PASS_CALL2 + */ + cil_log(CIL_INFO, "Resetting declarations\n"); + + if (pass >= CIL_PASS_MISC1) { + __cil_ordered_lists_reset(&extra_args.sidorder_lists); + __cil_ordered_lists_reset(&extra_args.classorder_lists); + __cil_ordered_lists_reset(&extra_args.unordered_classorder_lists); + __cil_ordered_lists_reset(&extra_args.catorder_lists); + __cil_ordered_lists_reset(&extra_args.sensitivityorder_lists); + cil_list_destroy(&db->sidorder, CIL_FALSE); + cil_list_destroy(&db->classorder, CIL_FALSE); + cil_list_destroy(&db->catorder, CIL_FALSE); + cil_list_destroy(&db->sensitivityorder, CIL_FALSE); + } - rc = cil_reset_ast(current); - if (rc != SEPOL_OK) { - cil_log(CIL_ERR, "Failed to reset declarations\n"); - goto exit; + pass = CIL_PASS_CALL1; + + rc = cil_reset_ast(current); + if (rc != SEPOL_OK) { + cil_log(CIL_ERR, "Failed to reset declarations\n"); + goto exit; + } } } cil_list_for_each(item, extra_args.to_destroy) { -- 2.26.3