From: Alan T. DeKok Date: Thu, 19 May 2022 15:38:07 +0000 (-0400) Subject: double-check and fix flags. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f588516d8fdc5b89cc1e4b99fb3ab6cacbc2aab0;p=thirdparty%2Ffreeradius-server.git double-check and fix flags. We now have a "can_purify" flag. This is set to "true" for pure functions which have pure arguments. And for alternations which have pure arguments. %% is set to pure. XLAT_BOX and XLAT_LITERAL are pure, but they are not "can_purify". The result is that we tell if there are portions of the tree which need additional work for purification. --- diff --git a/src/lib/unlang/xlat.h b/src/lib/unlang/xlat.h index 18cd8ea6825..c61773369e8 100644 --- a/src/lib/unlang/xlat.h +++ b/src/lib/unlang/xlat.h @@ -106,8 +106,8 @@ typedef struct { bool needs_resolving;//!< Needs pass2 resolution. bool needs_async; //!< Node and all child nodes are guaranteed to not ///< require asynchronous expansion. - bool pure; //!< has no external side effects - bool has_pure_children; //!< as the sticker says + bool pure; //!< has no external side effects, true for BOX, LITERAL, and some functions + bool can_purify; //!< if the xlat has a pure function with pure arguments. } xlat_flags_t; /* diff --git a/src/lib/unlang/xlat_priv.h b/src/lib/unlang/xlat_priv.h index 67581289bc1..4ce34148576 100644 --- a/src/lib/unlang/xlat_priv.h +++ b/src/lib/unlang/xlat_priv.h @@ -178,7 +178,7 @@ static inline CC_HINT(nonnull) void xlat_flags_merge(xlat_flags_t *parent, xlat_ parent->needs_resolving |= child->needs_resolving; parent->pure &= child->pure; /* purity can only be removed, never added */ parent->pure &= !parent->needs_async; /* things needing async cannot be pure */ - parent->has_pure_children |= child->pure | child->has_pure_children; + parent->can_purify |= child->can_purify; } /** Set the type of an xlat node diff --git a/src/lib/unlang/xlat_tokenize.c b/src/lib/unlang/xlat_tokenize.c index a39c7f2e19b..2885cdecdcb 100644 --- a/src/lib/unlang/xlat_tokenize.c +++ b/src/lib/unlang/xlat_tokenize.c @@ -128,6 +128,12 @@ xlat_exp_t *xlat_exp_func_alloc(TALLOC_CTX *ctx, xlat_t *func, xlat_exp_head_t c node->flags = func->flags; xlat_flags_merge(&node->flags, &args->flags); + /* + * If the function is pure, AND it's arguments are pure, + * then remember that we need to call a pure function. + */ + node->flags.can_purify = func->flags.pure && args->flags.pure; + return node; } @@ -175,6 +181,14 @@ static inline int xlat_tokenize_alternation(xlat_exp_head_t *head, fr_sbuff_t *i } node->flags = node->alternate[0]->flags; + /* + * If the first argument is pure, then we can purify this + * node. If the first argument isn't pure, but the + * second one is, then we can still purify the second + * argument. + */ + node->flags.can_purify |= node->alternate[0]->flags.pure; + /* * Allow the RHS to be empty as a special case. */ @@ -197,6 +211,7 @@ static inline int xlat_tokenize_alternation(xlat_exp_head_t *head, fr_sbuff_t *i goto error; } xlat_flags_merge(&node->flags, &node->alternate[1]->flags); + node->flags.can_purify |= node->alternate[1]->flags.pure; done: xlat_exp_insert_tail(head, node); @@ -498,7 +513,11 @@ int xlat_tokenize_function_args(xlat_exp_head_t *head, fr_sbuff_t *in, /* * Check we have all the required arguments */ - if ((node->type == XLAT_FUNC) && (xlat_validate_function_args(node) < 0)) goto error; + if (node->type == XLAT_FUNC) { + if (xlat_validate_function_args(node) < 0) goto error; + + node->flags.can_purify = node->call.func->flags.pure && node->call.args->flags.pure; + } if (!fr_sbuff_next_if_char(in, ')')) { fr_strerror_const("Missing closing brace"); @@ -931,8 +950,11 @@ static int xlat_tokenize_string(xlat_exp_head_t *head, xlat_exp_set_type(node, XLAT_ONE_LETTER); xlat_exp_set_name_buffer_shallow(node, str); - node->flags.pure = true; /* value boxes are always pure */ - node->flags.needs_async = false; /* value boxes are always non-async */ + /* + * %% is pure. Everything else is not. + */ + node->flags.pure = (node->fmt[0] == '%'); + node->flags.needs_async = false; xlat_exp_insert_tail(head, node); continue; @@ -1633,6 +1655,8 @@ int xlat_resolve(xlat_exp_head_t *head, xlat_res_rules_t const *xr_rules) if (xlat_resolve(node->call.args, xr_rules) < 0) return -1; node->flags = node->call.func->flags; xlat_flags_merge(&node->flags, &node->call.args->flags); + + node->flags.can_purify = node->call.func->flags.pure && node->call.args->flags.pure; break; /* @@ -1706,6 +1730,8 @@ int xlat_resolve(xlat_exp_head_t *head, xlat_res_rules_t const *xr_rules) */ xlat_flags_merge(&node->flags, &node->call.args->flags); + node->flags.can_purify = node->call.func->flags.pure && node->call.args->flags.pure; + /* * Add the freshly resolved function * to the bootstrap tree.