]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
expr: fix concat expression type propagation
authorPatrick McHardy <kaber@trash.net>
Sun, 14 Apr 2013 22:36:36 +0000 (00:36 +0200)
committerPatrick McHardy <kaber@trash.net>
Thu, 18 Apr 2013 13:28:46 +0000 (15:28 +0200)
Dynamically instantiate a data type to represent all types of a concatenation
and use that for type propagation.

include/datatype.h
src/datatype.c
src/evaluate.c
src/expression.c

index 538899349c68d6508d740ebab0dfadeeb8df4252..8a123631973808bf69831adf19a586322f470782 100644 (file)
@@ -117,6 +117,12 @@ extern struct error_record *symbol_parse(const struct expr *sym,
                                         struct expr **res);
 extern void datatype_print(const struct expr *expr);
 
+static inline bool datatype_equal(const struct datatype *d1,
+                                 const struct datatype *d2)
+{
+       return d1->type == d2->type;
+}
+
 /**
  * struct symbolic_constant - symbol <-> constant mapping
  *
@@ -168,4 +174,7 @@ extern const struct datatype inet_service_type;
 extern const struct datatype mark_type;
 extern const struct datatype time_type;
 
+extern const struct datatype *concat_type_alloc(const struct expr *expr);
+extern void concat_type_destroy(const struct datatype *dtype);
+
 #endif /* NFTABLES_DATATYPE_H */
index e87de41861784f1b89870ee5ada010f8bee51519..3a2f19d83a35f6ffed186896338f24e4881de29d 100644 (file)
@@ -23,6 +23,7 @@
 #include <erec.h>
 
 static const struct datatype *datatypes[TYPE_MAX + 1] = {
+       [TYPE_INVALID]          = &invalid_type,
        [TYPE_VERDICT]          = &verdict_type,
        [TYPE_BITMASK]          = &bitmask_type,
        [TYPE_INTEGER]          = &integer_type,
@@ -642,3 +643,39 @@ const struct datatype time_type = {
        .basetype       = &integer_type,
        .print          = time_type_print,
 };
+
+static struct error_record *concat_type_parse(const struct expr *sym,
+                                             struct expr **res)
+{
+       return error(&sym->location, "invalid data type, expected %s",
+                    sym->dtype->desc);
+}
+
+const struct datatype *concat_type_alloc(const struct expr *expr)
+{
+       struct datatype *dtype;
+       struct expr *i;
+       char desc[256] = "concatenation of ";
+       unsigned int type = 0;
+
+       list_for_each_entry(i, &expr->expressions, list) {
+               if (type != 0)
+                       strncat(desc, ", ", sizeof(desc) - strlen(desc) - 1);
+               strncat(desc, i->dtype->desc, sizeof(desc) - strlen(desc) - 1);
+
+               type <<= 8;
+               type  |= i->dtype->type;
+       }
+
+       dtype           = xzalloc(sizeof(*dtype));
+       dtype->type     = type;
+       dtype->desc     = xstrdup(desc);
+       dtype->parse    = concat_type_parse;
+
+       return dtype;
+}
+
+void concat_type_destroy(const struct datatype *dtype)
+{
+       xfree(dtype);
+}
index 638a0fcbc0965a13c012ce09ba36e13abb1a55d3..6adf663df82225e38fcbadaa6a935db7ab10ff6d 100644 (file)
@@ -583,16 +583,29 @@ static int list_member_evaluate(struct eval_ctx *ctx, struct expr **expr)
 
 static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
 {
-       unsigned int flags = EXPR_F_CONSTANT;
+       const struct datatype *dtype = ctx->ectx.dtype, *tmp;
+       unsigned int type = dtype ? dtype->type : 0;
+       unsigned int flags = EXPR_F_CONSTANT | EXPR_F_SINGLETON;
        struct expr *i, *next;
+       unsigned int n;
 
+       n = 1;
        list_for_each_entry_safe(i, next, &(*expr)->expressions, list) {
+               tmp = datatype_lookup((type >> 8 * ((*expr)->size - n)) & 0xff);
+               expr_set_context(&ctx->ectx, tmp, tmp->size);
+
                if (list_member_evaluate(ctx, &i) < 0)
                        return -1;
                flags &= i->flags;
+
+               n++;
        }
 
        (*expr)->flags |= flags;
+       (*expr)->dtype = concat_type_alloc(*expr);
+
+       expr_set_context(&ctx->ectx, (*expr)->dtype, (*expr)->len);
+
        return 0;
 }
 
@@ -865,7 +878,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
                if (right->ops->type == EXPR_SET)
                        right = rel->right =
                                implicit_set_declaration(ctx, left->dtype, left->len, right);
-               else if (left->dtype != right->dtype)
+               else if (!datatype_equal(left->dtype, right->dtype))
                        return expr_binary_error(ctx, right, left,
                                                 "datatype mismatch, expected %s, "
                                                 "set has type %s",
@@ -880,7 +893,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
                left = rel->left;
                break;
        case OP_EQ:
-               if (left->dtype != right->dtype)
+               if (!datatype_equal(left->dtype, right->dtype))
                        return expr_binary_error(ctx, right, left,
                                                 "datatype mismatch, expected %s, "
                                                 "expression has type %s",
@@ -897,12 +910,14 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
                case EXPR_META:
                        payload_ctx_update_meta(&ctx->pctx, rel);
                        break;
+               case EXPR_CONCAT:
+                       return 0;
                default:
                        break;
                }
        case OP_NEQ:
        case OP_FLAGCMP:
-               if (left->dtype != right->dtype)
+               if (!datatype_equal(left->dtype, right->dtype))
                        return expr_binary_error(ctx, right, left,
                                                 "datatype mismatch, expected %s, "
                                                 "expression has type %s",
@@ -928,7 +943,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
        case OP_GT:
        case OP_LTE:
        case OP_GTE:
-               if (left->dtype != right->dtype)
+               if (datatype_equal(left->dtype, right->dtype))
                        return expr_binary_error(ctx, right, left,
                                                 "datatype mismatch, expected %s, "
                                                 "expression has type %s",
@@ -959,7 +974,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
                        return -1;
                break;
        case OP_RANGE:
-               if (left->dtype != right->dtype)
+               if (datatype_equal(left->dtype, right->dtype))
                        return expr_binary_error(ctx, right, left,
                                                 "datatype mismatch, expected %s, "
                                                 "expression has type %s",
index 0bd2bb43f620ae10fc5e78c7bcf606469c5bc923..8cf3f621743d33798ed3e5f3dd8ed5f3d9269010 100644 (file)
@@ -566,6 +566,12 @@ void compound_expr_remove(struct expr *compound, struct expr *expr)
        list_del(&expr->list);
 }
 
+static void concat_expr_destroy(struct expr *expr)
+{
+       concat_type_destroy(expr->dtype);
+       compound_expr_destroy(expr);
+}
+
 static void concat_expr_print(const struct expr *expr)
 {
        compound_expr_print(expr, " . ");
@@ -576,7 +582,7 @@ static const struct expr_ops concat_expr_ops = {
        .name           = "concat",
        .print          = concat_expr_print,
        .clone          = compound_expr_clone,
-       .destroy        = compound_expr_destroy,
+       .destroy        = concat_expr_destroy,
 };
 
 struct expr *concat_expr_alloc(const struct location *loc)