summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2013-04-15 00:36:36 +0200
committerPatrick McHardy <kaber@trash.net>2013-04-18 15:28:46 +0200
commit84cf34938294e404fd7e9ebe1a630fe868ae22da (patch)
tree040ef41daf17fee350c294ed19d409d1a651a299
parenta711ab22a58504e52c33f5fd939643002d7e6a81 (diff)
expr: fix concat expression type propagation
Dynamically instantiate a data type to represent all types of a concatenation and use that for type propagation.
-rw-r--r--include/datatype.h9
-rw-r--r--src/datatype.c37
-rw-r--r--src/evaluate.c27
-rw-r--r--src/expression.c8
4 files changed, 74 insertions, 7 deletions
diff --git a/include/datatype.h b/include/datatype.h
index 53889934..8a123631 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -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 */
diff --git a/src/datatype.c b/src/datatype.c
index e87de418..3a2f19d8 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -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);
+}
diff --git a/src/evaluate.c b/src/evaluate.c
index 638a0fcb..6adf663d 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -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",
diff --git a/src/expression.c b/src/expression.c
index 0bd2bb43..8cf3f621 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -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)