From 84cf34938294e404fd7e9ebe1a630fe868ae22da Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 15 Apr 2013 00:36:36 +0200 Subject: expr: fix concat expression type propagation Dynamically instantiate a data type to represent all types of a concatenation and use that for type propagation. --- include/datatype.h | 9 +++++++++ src/datatype.c | 37 +++++++++++++++++++++++++++++++++++++ src/evaluate.c | 27 +++++++++++++++++++++------ src/expression.c | 8 +++++++- 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 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) -- cgit v1.2.3