]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
xlat: Automatically alloc list heads
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sun, 19 Feb 2023 18:18:53 +0000 (12:18 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Sun, 19 Feb 2023 22:55:39 +0000 (16:55 -0600)
src/lib/server/tmpl_tokenize.c
src/lib/unlang/all.mk
src/lib/unlang/xlat.h
src/lib/unlang/xlat_alloc.c [new file with mode: 0644]
src/lib/unlang/xlat_expr.c
src/lib/unlang/xlat_inst.c
src/lib/unlang/xlat_priv.h
src/lib/unlang/xlat_purify.c
src/lib/unlang/xlat_tokenize.c

index 24860df438a1e6c99c3bcb7b720caa1b553721c1..ac77ce427689430764b6c8e7e5bf315c743b338f 100644 (file)
@@ -3198,7 +3198,7 @@ tmpl_t *tmpl_copy(TALLOC_CTX *ctx, tmpl_t const *in)
        /*
         *      Copy the xlat component
         */
-       if (tmpl_contains_xlat(vpt) && unlikely(xlat_copy(vpt, &vpt->data.xlat.ex, in->data.xlat.ex) < 0)) goto error;
+       if (tmpl_contains_xlat(vpt) && unlikely(xlat_copy(vpt, vpt->data.xlat.ex, in->data.xlat.ex) < 0)) goto error;
 
        return vpt;
 }
index 148748918ef93a071a53823adaffe338b3f71dca..007a6f2497d31e415dae70565ff36f3c625f8f12 100644 (file)
@@ -26,12 +26,13 @@ SOURCES     :=      base.c \
                tmpl.c \
                variable.c \
                xlat.c \
+               xlat_alloc.c \
                xlat_builtin.c \
                xlat_eval.c \
                xlat_expr.c \
                xlat_inst.c \
-               xlat_tokenize.c \
                xlat_pair.c \
+               xlat_tokenize.c \
                xlat_purify.c
 
 HEADERS                := $(subst src/lib/,,$(wildcard src/lib/unlang/*.h))
index ee07321cb34d8b58e4e4c2d809f26b23985ad871..c077d7daa8319c5443cad6ea5db2a27b574003fc 100644 (file)
@@ -480,7 +480,7 @@ tmpl_t              *xlat_to_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_head_t *xlat);
 
 int            xlat_from_tmpl_attr(TALLOC_CTX *ctx, xlat_exp_head_t **head, tmpl_t **vpt_p);
 
-int            xlat_copy(TALLOC_CTX *ctx, xlat_exp_head_t **out, xlat_exp_head_t const *in);
+int            xlat_copy(TALLOC_CTX *ctx, xlat_exp_head_t *out, xlat_exp_head_t const *in);
 
 /*
  *     xlat_inst.c
diff --git a/src/lib/unlang/xlat_alloc.c b/src/lib/unlang/xlat_alloc.c
new file mode 100644 (file)
index 0000000..4a7dc53
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file xlat_alloc.c
+ * @brief Functions to allocate different types of xlat nodes
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/server/base.h>
+#include <freeradius-devel/unlang/xlat.h>
+
+#include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/util/types.h>
+
+#define _XLAT_PRIVATE
+#include <freeradius-devel/unlang/xlat_priv.h>
+
+xlat_exp_head_t *_xlat_exp_head_alloc(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx)
+{
+       xlat_exp_head_t *head;
+
+       MEM(head = talloc_zero(ctx, xlat_exp_head_t));
+
+       fr_dlist_init(&head->dlist, xlat_exp_t, entry);
+       head->flags.pure = true;
+#ifndef NDEBUG
+       head->file = file;
+       head->line = line;
+#endif
+
+       return head;
+}
+
+/** Set the type of an xlat node
+ *
+ * Also initialises any xlat_exp_head necessary
+ *
+ * @param[in] node     to set type for.
+ * @param[in] type     to set.
+ */
+void _xlat_exp_set_type(NDEBUG_LOCATION_ARGS xlat_exp_t *node, xlat_type_t type)
+{
+       /*
+        *      Do nothing if it's the same type
+        */
+       if (node->type == type) return;
+
+       /*
+        *      Free existing lists if present
+        */
+       if (node->type != 0) switch (node->type) {
+       case XLAT_ALTERNATE:
+               TALLOC_FREE(node->alternate[0]);
+               TALLOC_FREE(node->alternate[1]);
+               break;
+
+       case XLAT_GROUP:
+               TALLOC_FREE(node->group);
+               break;
+
+       case XLAT_FUNC:
+       case XLAT_FUNC_UNRESOLVED:
+               if (type != XLAT_FUNC) {
+                       TALLOC_FREE(node->call.args); /* Just switching from unresolved to resolved */
+               } else goto done;
+               break;
+
+       default:
+               break;
+       }
+
+       /*
+        *      Alloc new lists to match the type
+        */
+       switch (type) {
+       case XLAT_ALTERNATE:
+               node->alternate[0] = _xlat_exp_head_alloc(NDEBUG_LOCATION_VALS node);
+               node->alternate[1] = _xlat_exp_head_alloc(NDEBUG_LOCATION_VALS node);
+               break;
+
+       case XLAT_GROUP:
+               node->group = _xlat_exp_head_alloc(NDEBUG_LOCATION_VALS node);
+               break;
+
+       case XLAT_FUNC:
+       case XLAT_FUNC_UNRESOLVED:
+               node->call.args = _xlat_exp_head_alloc(NDEBUG_LOCATION_VALS node);
+               break;
+
+       default:
+               break;
+       }
+
+done:
+       node->type = type;
+}
+
+static xlat_exp_t *xlat_exp_alloc_pool(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, unsigned int extra_hdrs, size_t extra)
+{
+       xlat_exp_t *node;
+
+       MEM(node = talloc_zero_pooled_object(ctx, xlat_exp_t, extra_hdrs, extra));
+       node->flags.pure = true;        /* everything starts pure */
+       node->quote = T_BARE_WORD;
+#ifndef NDEBUG
+       node->file = file;
+       node->line = line;
+#endif
+
+       return node;
+}
+
+/** Allocate an xlat node with no name, and no type set
+ *
+ * @param[in] ctx      to allocate node in.
+ * @return A new xlat node.
+ */
+xlat_exp_t *_xlat_exp_alloc_null(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx)
+{
+       return xlat_exp_alloc_pool(NDEBUG_LOCATION_VALS ctx, 0, 0);
+}
+
+/** Allocate an xlat node
+ *
+ * @param[in] ctx      to allocate node in.
+ * @param[in] type     of the node.
+ * @param[in] in       original input string.
+ * @param[in] inlen    the length of the original input string.
+ * @return A new xlat node.
+ */
+xlat_exp_t *_xlat_exp_alloc(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, xlat_type_t type, char const *in, size_t inlen)
+{
+       xlat_exp_t *node;
+       unsigned int extra_hdrs;
+       size_t extra;
+
+       /*
+        *      Figure out how much extra memory we
+        *      need to allocate for this node type.
+        */
+       switch (type) {
+       case XLAT_ALTERNATE:
+               extra_hdrs = 2;
+               extra = sizeof(xlat_exp_head_t) * 2;
+               break;
+
+       case XLAT_GROUP:
+               extra_hdrs = 1;
+               extra = sizeof(xlat_exp_head_t);
+               break;
+
+       case XLAT_FUNC:
+               extra_hdrs = 1;
+               extra = sizeof(xlat_exp_head_t);
+               break;
+
+       default:
+               extra_hdrs = 0;
+               extra = 0;
+       }
+
+       node = xlat_exp_alloc_pool(NDEBUG_LOCATION_VALS
+                                  ctx,
+                                  (in != NULL) + extra_hdrs,
+                                  inlen + extra);
+       _xlat_exp_set_type(NDEBUG_LOCATION_VALS node, type);
+
+       if (!in) return node;
+
+       node->fmt = talloc_bstrndup(node, in, inlen);
+       switch (type) {
+       case XLAT_BOX:
+               fr_value_box_strdup_shallow(&node->data, NULL, node->fmt, false);
+               break;
+
+       default:
+               break;
+       }
+
+       return node;
+}
+
+/** Set the format string for an xlat node
+ *
+ * @param[in] node     to set fmt for.
+ * @param[in] fmt      talloced buffer to set as the fmt string.
+ */
+void xlat_exp_set_name_buffer_shallow(xlat_exp_t *node, char const *fmt)
+{
+       if (node->fmt) talloc_const_free(node->fmt);
+       node->fmt = talloc_get_type_abort(fmt, char);
+}
index c5b97fa8efd5524a9c3fadc80f3ec0ff784eebd7..5d43cdc6009d91ac5aec37b0f076c39a38bd6620 100644 (file)
@@ -89,7 +89,7 @@ static void xlat_func_append_arg(xlat_exp_t *head, xlat_exp_t *node, bool exists
        group = xlat_exp_alloc(head->call.args, XLAT_GROUP, NULL, 0);
        group->quote = T_BARE_WORD;
 
-       group->fmt = node->fmt; /* not entirely correct, but good enough for now */
+       xlat_exp_set_name_buffer_shallow(group, node->fmt); /* not entirely correct, but good enough for now */
        group->flags = node->flags;
 
        talloc_steal(group->group, node);
@@ -121,7 +121,7 @@ static xlat_exp_t *xlat_exists_alloc(TALLOC_CTX *ctx, xlat_exp_t *child)
 
        fr_assert(child->type == XLAT_TMPL);
        fr_assert(tmpl_contains_attr(child->vpt));
-       node->fmt = child->vpt->name;
+       xlat_exp_set_name_buffer_shallow(node, child->vpt->name);
 
        xlat_func_append_arg(node, child, false);
 
@@ -890,7 +890,7 @@ static int xlat_instantiate_logical(xlat_inst_ctx_t const *xctx)
  *     result is "false" for "delete this argument"
  *     result is "true" for "return this argument".
  */
-static bool xlat_node_matches_bool(xlat_exp_t *parent, xlat_exp_head_t *head, bool sense, bool *result)
+static bool xlat_node_matches_bool(bool *result, xlat_exp_t *parent, xlat_exp_head_t *head, bool sense)
 {
        fr_value_box_t *box;
        xlat_exp_t *node;
@@ -929,7 +929,7 @@ check:
 
        xlat_inst_remove(parent);
 
-       parent->type = XLAT_BOX;
+       xlat_exp_set_type(parent, XLAT_BOX);
        fr_value_box_copy(parent, &parent->data, box);
        parent->flags = (xlat_flags_t) { .pure = true, .constant = true, };
 
@@ -969,17 +969,17 @@ static void xlat_ungroup(xlat_exp_head_t *head)
  */
 static int xlat_expr_logical_purify(xlat_exp_t *node, void *instance, request_t *request)
 {
-       int i, j;
-       int deleted = 0;
-       bool result;
-       xlat_logical_inst_t *inst = talloc_get_type_abort(instance, xlat_logical_inst_t);
-       xlat_exp_head_t *group;
+       int                     i, j;
+       int                     deleted = 0;
+       bool                    result;
+       xlat_logical_inst_t     *inst = talloc_get_type_abort(instance, xlat_logical_inst_t);
+       xlat_exp_head_t         *group;
 
        fr_assert(node->type == XLAT_FUNC);
 
        /*
-        *      Don't check the last argument.  If everything else gets deleted, then we just return the last
-        *      argument.
+        *      Don't check the last argument.  If everything else gets deleted,
+        *      then we just return the last argument.
         */
        for (i = 0; i < inst->argc; i++) {
                /*
@@ -1002,9 +1002,7 @@ static int xlat_expr_logical_purify(xlat_exp_t *node, void *instance, request_t
                 *      result is "false" for "delete this argument"
                 *      result is "true" for "return this argument".
                 */
-               if (!xlat_node_matches_bool(node, inst->argv[i], inst->stop_on_match, &result)) {
-                       continue;
-               }
+               if (!xlat_node_matches_bool(&result, node, inst->argv[i], inst->stop_on_match)) continue;
 
                /*
                 *      0 && EXPR --> 0.
@@ -1068,11 +1066,12 @@ static int xlat_expr_logical_purify(xlat_exp_t *node, void *instance, request_t
         */
        group = inst->argv[0];
        fr_assert(group != NULL);
+       fr_assert(group->fmt != NULL);
        talloc_steal(node, group);
 
        xlat_inst_remove(node);
-       node->type = XLAT_GROUP;
-       node->fmt = group->fmt;
+       xlat_exp_set_type(node, XLAT_BOX);
+       xlat_exp_set_name_buffer_shallow(node, group->fmt);
        node->group = group;
        node->flags = group->flags;
 
@@ -1940,8 +1939,7 @@ static fr_slen_t tokenize_unary(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuf
         */
        *out_c = c;
 
-       MEM(unary = xlat_exp_alloc(head, XLAT_FUNC, func->name, strlen(func->name)));
-       unary->fmt = fr_tokens[func->token];
+       MEM(unary = xlat_exp_alloc(head, XLAT_FUNC, fr_tokens[func->token], strlen(fr_tokens[func->token])));
        unary->call.func = func;
        unary->flags = func->flags;
 
@@ -2007,9 +2005,8 @@ static xlat_exp_t *expr_cast_alloc(TALLOC_CTX *ctx, fr_type_t type)
        MEM(node = xlat_exp_alloc(cast, XLAT_BOX, NULL, 0));
        node->flags.constant = true;
        xlat_exp_set_name_buffer_shallow(node,
-                                        talloc_strdup(node,
-                                                      fr_table_str_by_value(fr_type_table,
-                                                                            type, "<INVALID>")));
+                                        talloc_typed_strdup(node,
+                                                            fr_table_str_by_value(fr_type_table, type, "<INVALID>")));
 
        fr_value_box_init(&node->data, FR_TYPE_UINT8, attr_cast_base, false);
        node->data.vb_uint8 = type;
@@ -2145,7 +2142,7 @@ static fr_slen_t tokenize_regex_rhs(xlat_exp_head_t *head, xlat_exp_t **out, fr_
 
        node->vpt = vpt;
        node->quote = quote;
-       node->fmt = vpt->name;
+       xlat_exp_set_name_buffer_shallow(node, vpt->name);
 
        node->flags.pure = !tmpl_contains_xlat(node->vpt);
        node->flags.needs_resolving = tmpl_needs_resolving(node->vpt);
@@ -2311,17 +2308,9 @@ static fr_slen_t tokenize_field(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuf
         */
        if (tmpl_is_xlat(vpt) || tmpl_is_xlat_unresolved(vpt)) {
                xlat_exp_head_t *xlat = tmpl_xlat(vpt);
-               xlat_exp_t *cast;
-               fr_type_t type = FR_TYPE_NULL;
-
-               talloc_steal(node, xlat);
-               node->fmt = talloc_typed_strdup(node, vpt->name);
-
-               xlat_exp_set_type(node, XLAT_GROUP);
-               node->quote = quote;
-               node->group = xlat;
-
-               node->flags = xlat->flags;
+               fr_type_t       type = FR_TYPE_NULL;
+               xlat_exp_t      *arg = NULL;
+               xlat_exp_t      *cast = NULL;
 
                /*
                 *      Enforce a cast type.
@@ -2346,11 +2335,31 @@ static fr_slen_t tokenize_field(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuf
 
                if (type != FR_TYPE_NULL) {
                        MEM(cast = expr_cast_alloc(head, type));
-                       xlat_func_append_arg(cast, node, false);
+                       head = cast->call.args; /* Arguments */
+               }
+
+               MEM(arg = xlat_exp_alloc(head, XLAT_GROUP, vpt->name, strlen(vpt->name)));
+
+               /*
+                *      This is less efficient than just stealing the
+                *      xlat into the context of the new node...
+                *
+                *      But talloc_steal can be extremely inefficient O(N)
+                *      where N is chunk siblings.
+                */
+               xlat_copy(arg->group, arg->group, xlat);
+               arg->quote = quote;
+               arg->flags = xlat->flags;
+
+               talloc_free(node);      /* also frees tmpl, leaving just the xlat */
+
+               if (cast) {
+                       xlat_func_append_arg(cast, arg, false);
                        node = cast;
+               } else {
+                       node = arg;
                }
 
-               talloc_free(vpt);
                goto done;
        }
 
@@ -2372,7 +2381,7 @@ static fr_slen_t tokenize_field(xlat_exp_head_t *head, xlat_exp_t **out, fr_sbuf
         */
        node->vpt = vpt;
        node->quote = quote;
-       node->fmt = vpt->name;
+       xlat_exp_set_name_buffer_shallow(node, vpt->name);
 
        node->flags.pure = tmpl_is_data(node->vpt);
        node->flags.constant = node->flags.pure;
@@ -2694,7 +2703,6 @@ redo:
         *      Create the function node, with the LHS / RHS arguments.
         */
        MEM(node = xlat_exp_alloc(head, XLAT_FUNC, fr_tokens[op], strlen(fr_tokens[op])));
-       node->fmt = fr_tokens[op];
        node->call.func = func;
        node->flags = func->flags;
 
index b8475027b0677a72c799081899e499cad35d2e8b..a7ef6b977aa75e5efa5a5b78b39097623cc7fabb 100644 (file)
@@ -641,7 +641,5 @@ int xlat_inst_remove(xlat_exp_t *node)
                TALLOC_FREE(node->call.inst);
        }
 
-
-       node->type = XLAT_INVALID;
        return 0;
 }
index d65947c0b0d9c9b044a43f1c2cc6dc30f081eb17..27ffc8c6d4919008925d3e77ae954d5d22a36f0b 100644 (file)
@@ -34,6 +34,7 @@ extern "C" {
 #include <freeradius-devel/unlang/xlat.h>
 #include <freeradius-devel/io/pair.h>
 #include <freeradius-devel/util/talloc.h>
+#include <freeradius-devel/build.h>
 
 #ifdef DEBUG_XLAT
 #  define XLAT_DEBUG RDEBUG3
@@ -41,6 +42,18 @@ extern "C" {
 #  define XLAT_DEBUG(...)
 #endif
 
+/*
+ *     Allow public and private versions of the same structures
+ */
+#ifdef _CONST
+#  error _CONST can only be defined in the local header
+#endif
+#ifndef _XLAT_PRIVATE
+#  define _CONST const
+#else
+#  define _CONST
+#endif
+
 typedef fr_slen_t (*xlat_print_t)(fr_sbuff_t *in, xlat_exp_t const *self, void *inst, fr_sbuff_escape_rules_t const *e_rules);
 typedef int (*xlat_resolve_t)(xlat_exp_t *self, void *inst, xlat_res_rules_t const *xr_rules);
 typedef int (*xlat_purify_t)(xlat_exp_t *self, void *inst, request_t *request);
@@ -125,13 +138,18 @@ typedef struct {
  * These nodes form a tree which represents one or more nested expansions.
  */
 struct xlat_exp_s {
-       char const      *fmt;           //!< The original format string (a talloced buffer).
-       fr_token_t      quote;          //!< Type of quoting around XLAT_GROUP types.
+       char const *  _CONST    fmt;            //!< The original format string (a talloced buffer).
+       fr_token_t              quote;          //!< Type of quoting around XLAT_GROUP types.
+
+       xlat_flags_t            flags;          //!< Flags that control resolution and evaluation.
 
-       xlat_flags_t    flags;          //!< Flags that control resolution and evaluation.
+       xlat_type_t _CONST      type;           //!< type of this expansion.
+       fr_dlist_t              entry;
 
-       xlat_type_t     type;           //!< type of this expansion.
-       fr_dlist_t      entry;
+#ifndef NDEBUG
+       char const * _CONST     file;           //!< File where the xlat was allocated.
+       int                     line;           //!< Line where the xlat was alocated.
+#endif
 
        union {
                xlat_exp_head_t *alternate[2];  //!< alternate expansions
@@ -160,11 +178,16 @@ struct xlat_exp_s {
 };
 
 struct xlat_exp_head_s {
-       char const      *fmt;           //!< The original format string (a talloced buffer).
-       xlat_flags_t    flags;          //!< Flags that control resolution and evaluation.
-       bool            instantiated;   //!< temporary flag until we fix more things
-       fr_dict_t const *dict;          //!< dictionary for this xlat
-       fr_dlist_head_t dlist;
+       fr_dlist_head_t         dlist;
+       char const * _CONST     fmt;            //!< The original format string (a talloced buffer).
+       xlat_flags_t            flags;          //!< Flags that control resolution and evaluation.
+       bool                    instantiated;   //!< temporary flag until we fix more things
+       fr_dict_t const         *dict;          //!< dictionary for this xlat
+
+#ifndef NDEBUG
+       char const * _CONST     file;           //!< File where the xlat was allocated.
+       int                     line;           //!< Line where the xlat was alocated.
+#endif
 };
 
 
@@ -217,146 +240,6 @@ static inline xlat_exp_t *xlat_exp_next(xlat_exp_head_t const *head, xlat_exp_t
        return fr_dlist_next(&head->dlist, node);
 }
 
-static inline xlat_exp_head_t *xlat_exp_head_alloc(TALLOC_CTX *ctx)
-{
-       xlat_exp_head_t *head;
-
-       MEM(head = talloc_zero(ctx, xlat_exp_head_t));
-
-       fr_dlist_init(&head->dlist, xlat_exp_t, entry);
-       head->flags.pure = true;
-
-       return head;
-}
-
-/** Set the type of an xlat node
- *
- * Also initialises any xlat_exp_head necessary
- *
- * @param[in] node     to set type for.
- * @param[in] type     to set.
- */
-static inline void xlat_exp_set_type(xlat_exp_t *node, xlat_type_t type)
-{
-       xlat_type_t existing_type = node->type;
-
-       node->type = type;
-
-       if (existing_type != 0) return;
-
-       switch (type) {
-       case XLAT_ALTERNATE:
-               node->alternate[0] = xlat_exp_head_alloc(node);
-               node->alternate[1] = xlat_exp_head_alloc(node);
-               break;
-
-       case XLAT_GROUP:
-               node->group = xlat_exp_head_alloc(node);
-               break;
-
-       case XLAT_FUNC:
-       case XLAT_FUNC_UNRESOLVED:
-               node->call.args = xlat_exp_head_alloc(node);
-               break;
-
-       default:
-               break;
-       }
-}
-
-static inline xlat_exp_t *xlat_exp_alloc_pool(TALLOC_CTX *ctx, unsigned int extra_hdrs, size_t extra)
-{
-       xlat_exp_t *node;
-
-       MEM(node = talloc_zero_pooled_object(ctx, xlat_exp_t, extra_hdrs, extra));
-       node->flags.pure = true;        /* everything starts pure */
-       node->quote = T_BARE_WORD;
-
-       return node;
-}
-
-/** Allocate an xlat node with no name, and no type set
- *
- * @param[in] ctx      to allocate node in.
- * @return A new xlat node.
- */
-static inline xlat_exp_t *xlat_exp_alloc_null(TALLOC_CTX *ctx)
-{
-       return xlat_exp_alloc_pool(ctx, 0, 0);
-}
-
-/** Allocate an xlat node
- *
- * @param[in] ctx      to allocate node in.
- * @param[in] type     of the node.
- * @param[in] in       original input string.
- * @param[in] inlen    the length of the original input string.
- * @return A new xlat node.
- */
-static inline xlat_exp_t *xlat_exp_alloc(TALLOC_CTX *ctx, xlat_type_t type,
-                                        char const *in, size_t inlen)
-{
-       xlat_exp_t *node;
-       unsigned int extra_hdrs;
-       size_t extra;
-
-       /*
-        *      Figure out how much extra memory we
-        *      need to allocate for this node type.
-        */
-       switch (type) {
-       case XLAT_ALTERNATE:
-               extra_hdrs = 2;
-               extra = sizeof(xlat_exp_head_t) * 2;
-               break;
-
-       case XLAT_GROUP:
-               extra_hdrs = 1;
-               extra = sizeof(xlat_exp_head_t);
-               break;
-
-       case XLAT_FUNC:
-               extra_hdrs = 1;
-               extra = sizeof(xlat_exp_head_t);
-               break;
-       
-       default:
-               extra_hdrs = 0;
-               extra = 0;
-       }
-
-       node = xlat_exp_alloc_pool(ctx,
-                                  (in != NULL) + extra_hdrs,
-                                  inlen + extra);
-       xlat_exp_set_type(node, type);
-
-       if (!in) return node;
-
-       node->fmt = talloc_bstrndup(node, in, inlen);
-       switch (type) {
-       case XLAT_BOX:
-               fr_value_box_strdup_shallow(&node->data, NULL, node->fmt, false);
-               break;
-
-       default:
-               break;
-       }
-
-       return node;
-}
-
-/** Set the format string for an xlat node
- *
- * @param[in] node     to set fmt for.
- * @param[in] fmt      talloced buffer to set as the fmt string.
- */
-static inline void xlat_exp_set_name_buffer_shallow(xlat_exp_t *node, char const *fmt)
-{
-       if (node->fmt) talloc_const_free(node->fmt);
-       node->fmt = fmt;
-}
-
-
 /** Mark an xlat function as internal
  *
  * @param[in] xlat to mark as internal.
@@ -411,10 +294,27 @@ int xlat_purify_list(xlat_exp_head_t *head, request_t *request);
  */
 typedef int (*xlat_walker_t)(xlat_exp_t *exp, void *uctx);
 
+/*
+ *     xlat_alloc.c
+ */
+xlat_exp_head_t        *_xlat_exp_head_alloc(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx);
+#define                xlat_exp_head_alloc(_ctx) _xlat_exp_head_alloc(NDEBUG_LOCATION_EXP _ctx)
+
+void           _xlat_exp_set_type(NDEBUG_LOCATION_ARGS xlat_exp_t *node, xlat_type_t type);
+#define                xlat_exp_set_type(_node, _type) _xlat_exp_set_type(NDEBUG_LOCATION_EXP _node, _type)
+
+xlat_exp_t     *_xlat_exp_alloc_null(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx);
+#define                xlat_exp_alloc_null(_ctx) _xlat_exp_alloc_null(NDEBUG_LOCATION_EXP _ctx)
+
+xlat_exp_t     *_xlat_exp_alloc(NDEBUG_LOCATION_ARGS TALLOC_CTX *ctx, xlat_type_t type, char const *in, size_t inlen);
+#define                xlat_exp_alloc(_ctx, _type, _in, _inlen) _xlat_exp_alloc(NDEBUG_LOCATION_EXP _ctx, _type, _in, _inlen)
+
+void           xlat_exp_set_name_buffer_shallow(xlat_exp_t *node, char const *fmt) CC_HINT(nonnull);
+
 /*
  *     xlat_func.c
  */
-xlat_t *xlat_func_find(char const *name, ssize_t namelen);
+xlat_t         *xlat_func_find(char const *name, ssize_t namelen);
 
 /*
  *     xlat_eval.c
@@ -450,9 +350,9 @@ void                unlang_xlat_init(void);
 int            unlang_xlat_push_node(TALLOC_CTX *ctx, bool *p_success, FR_DLIST_HEAD(fr_value_box_list) *out,
                                      request_t *request, xlat_exp_t *node);
 
-int xlat_decode_value_box_list(TALLOC_CTX *ctx, fr_pair_list_t *out,
-                              request_t *request, void *decode_ctx, fr_pair_decode_t decode,
-                              FR_DLIST_HEAD(fr_value_box_list) *in);
+int            xlat_decode_value_box_list(TALLOC_CTX *ctx, fr_pair_list_t *out,
+                                          request_t *request, void *decode_ctx, fr_pair_decode_t decode,
+                                          FR_DLIST_HEAD(fr_value_box_list) *in);
 /*
  *     xlat_expr.c
  */
index 42714a7431a791a37eedfddabd7224da2e7068cc..676a38a86129bb7c25aba151be7ecebf9e903fad 100644 (file)
@@ -38,15 +38,19 @@ static void xlat_value_list_to_xlat(xlat_exp_head_t *head, FR_DLIST_HEAD(fr_valu
        while ((box = fr_value_box_list_pop_head(list)) != NULL) {
                MEM(node = xlat_exp_alloc(head, XLAT_BOX, NULL, 0));
                fr_value_box_copy(node, &node->data, box);
-               talloc_free(box);
 
                if (node->data.type == FR_TYPE_STRING) {
                        node->quote = T_DOUBLE_QUOTED_STRING;
-                       node->fmt = node->data.vb_strvalue;
+                       xlat_exp_set_name_buffer_shallow(node, node->data.vb_strvalue);
                } else {
+                       char *name;
+
                        node->quote = T_BARE_WORD;
-                       node->fmt = ""; /* @todo - fixme? */
+                       fr_value_box_aprint(node, &name, box, NULL);
+
+                       xlat_exp_set_name_buffer_shallow(node, name);
                }
+               talloc_free(box);
 
                xlat_exp_insert_tail(head, node);
        }
@@ -57,7 +61,6 @@ int xlat_purify_list(xlat_exp_head_t *head, request_t *request)
 {
        int rcode;
        bool success;
-       xlat_exp_head_t *group;
        FR_DLIST_HEAD(fr_value_box_list) list;
        xlat_flags_t our_flags;
 
@@ -155,19 +158,13 @@ int xlat_purify_list(xlat_exp_head_t *head, request_t *request)
                        if (!success) return -1;
 
                        /*
-                        *      The function call becomes a GROUP of boxes.  We just re-use the argument head,
-                        *      which is already of the type we need.
+                        *      The function call becomes a GROUP of boxes
                         */
-                       /* coverity[dead_error_begin] */
-                       group = node->call.args;
-                       fr_dlist_talloc_free(&group->dlist);
-
                        xlat_inst_remove(node);
-                       node->type = XLAT_GROUP;
-                       node->group = group;
+                       xlat_exp_set_type(node, XLAT_GROUP);    /* Frees the argument list */
 
-                       xlat_value_list_to_xlat(group, &list);
-                       node->flags = group->flags;
+                       xlat_value_list_to_xlat(node->group, &list);
+                       node->flags = node->group->flags;
                        break;
                }
 
index 9f852e0dd0e432fb1ddb55f50d4898e365a62367..520ea0185e644b7c6bae109312739e9bf98e2023 100644 (file)
@@ -120,7 +120,7 @@ xlat_exp_t *xlat_exp_func_alloc(TALLOC_CTX *ctx, xlat_t *func, xlat_exp_head_t c
 
        MEM(node = xlat_exp_alloc(ctx, XLAT_FUNC, func->name, strlen(func->name)));
        node->call.func = func;
-       if (unlikely(xlat_copy(node, &node->call.args, args) < 0)) {
+       if (unlikely(xlat_copy(node, node->call.args, args) < 0)) {
                talloc_free(node);
                return NULL;
        }
@@ -284,7 +284,7 @@ static inline int xlat_tokenize_function_mono(xlat_exp_head_t *head,
                                              fr_sbuff_t *in,
                                              tmpl_rules_t const *t_rules)
 {
-       xlat_exp_t              *node, *arg_group;
+       xlat_exp_t              *node;
        xlat_t                  *func;
        fr_sbuff_marker_t       m_s;
 
@@ -1061,13 +1061,15 @@ static void _xlat_debug(xlat_exp_head_t const *head, int depth)
 
        fr_assert(head != NULL);
 
-       INFO_INDENT("head flags = { %s %s %s }",
-                   head->flags.needs_resolving ? "need_resolving" : "",
+       INFO_INDENT("head flags = %s %s %s",
+                   head->flags.needs_resolving ? "need_resolving," : "",
                    head->flags.pure ? "pure" : "",
                    head->flags.can_purify ? "can_purify" : "");
 
+       depth++;
+
        xlat_exp_foreach(head, node) {
-               INFO_INDENT("[%d] flags = { %s %s %s }", i++,
+               INFO_INDENT("[%d] flags = %s %s %s ", i++,
                            node->flags.needs_resolving ? "need_resolving" : "",
                            node->flags.pure ? "pure" : "",
                            node->flags.can_purify ? "can_purify" : "");
@@ -1080,6 +1082,9 @@ static void _xlat_debug(xlat_exp_head_t const *head, int depth)
                needs_resolving |= node->flags.needs_resolving;
 #endif
 
+               INFO_INDENT("{");
+               depth++;
+
                if (node->quote != T_BARE_WORD) INFO_INDENT("quote = %c", fr_token_quote[node->quote]);
 
                switch (node->type) {
@@ -1173,10 +1178,10 @@ static void _xlat_debug(xlat_exp_head_t const *head, int depth)
 
                case XLAT_ALTERNATE:
                        DEBUG("XLAT-IF {");
-                       _xlat_debug(node->alternate[0], depth + 1);
+                       _xlat_debug(node->alternate[0], depth);
                        DEBUG("}");
                        DEBUG("XLAT-ELSE {");
-                       _xlat_debug(node->alternate[1], depth + 1);
+                       _xlat_debug(node->alternate[1], depth);
                        DEBUG("}");
                        break;
 
@@ -1184,6 +1189,9 @@ static void _xlat_debug(xlat_exp_head_t const *head, int depth)
                        DEBUG("XLAT-INVALID");
                        break;
                }
+
+               depth--;
+               INFO_INDENT("}");
        }
 
        fr_assert(needs_resolving == head->flags.needs_resolving);
@@ -2047,17 +2055,13 @@ done:
  *     - 0 on success.
  *     - -1 on failure.
  */
-int xlat_copy(TALLOC_CTX *ctx, xlat_exp_head_t **out, xlat_exp_head_t const *in)
+int xlat_copy(TALLOC_CTX *ctx, xlat_exp_head_t *out, xlat_exp_head_t const *in)
 {
-       xlat_exp_head_t *head;
+       xlat_exp_head_t *head = NULL;
 
-       if (!in) {
-               *out = NULL;
-               return 0;
-       }
+       if (!in) return 0;
 
-       MEM(head = xlat_exp_head_alloc(ctx));
-       head->flags = in->flags;
+       xlat_flags_merge(&out->flags, &in->flags);
 
        /*
         *      Copy everything in the list of nodes
@@ -2065,7 +2069,14 @@ int xlat_copy(TALLOC_CTX *ctx, xlat_exp_head_t **out, xlat_exp_head_t const *in)
        xlat_exp_foreach(in, p) {
                xlat_exp_t *node;
 
-               MEM(node = xlat_exp_alloc(ctx, p->type, p->fmt, talloc_array_length(p->fmt) - 1));
+               (void)talloc_get_type_abort(p, xlat_exp_t);
+
+               /*
+                *      Ensure the format string is valid...  At this point
+                *      they should all be talloc'd strings.
+                */
+               MEM(node = xlat_exp_alloc(ctx, p->type,
+                                         talloc_get_type_abort(p->fmt, char), talloc_array_length(p->fmt) - 1));
                node->quote = p->quote;
                node->flags = p->flags;
 
@@ -2099,12 +2110,12 @@ int xlat_copy(TALLOC_CTX *ctx, xlat_exp_head_t **out, xlat_exp_head_t const *in)
                         */
                        node->call.func = p->call.func;
                        node->call.ephemeral = p->call.ephemeral;
-                       if (unlikely(xlat_copy(node, &node->call.args, p->call.args) < 0)) goto error;
+                       if (unlikely(xlat_copy(node, node->call.args, p->call.args) < 0)) goto error;
                        break;
 
                case XLAT_TMPL:
                        node->vpt = tmpl_copy(node, p->vpt);
-                       continue;
+                       break;
 
 #ifdef HAVE_REGEX
                case XLAT_REGEX:
@@ -2113,18 +2124,17 @@ int xlat_copy(TALLOC_CTX *ctx, xlat_exp_head_t **out, xlat_exp_head_t const *in)
 #endif
 
                case XLAT_ALTERNATE:
-                       if (unlikely(xlat_copy(node, &node->alternate[0], p->alternate[0]) < 0)) goto error;
-                       if (unlikely(xlat_copy(node, &node->alternate[1], p->alternate[1]) < 0)) goto error;
+                       if (unlikely(xlat_copy(node, node->alternate[0], p->alternate[0]) < 0)) goto error;
+                       if (unlikely(xlat_copy(node, node->alternate[1], p->alternate[1]) < 0)) goto error;
                        break;
 
                case XLAT_GROUP:
-                       if (unlikely(xlat_copy(node, &node->group, p->group) < 0)) goto error;
+                       if (unlikely(xlat_copy(node, node->group, p->group) < 0)) goto error;
                        break;
                }
 
-               xlat_exp_insert_tail(head, node);
+               xlat_exp_insert_tail(out, node);
        }
 
-       *out = head;
        return 0;
 }