Filter: Simple type checks converted to ARG() macro

This commit is contained in:
Jan Maria Matejka 2018-04-30 16:06:53 +02:00
parent 478f9babed
commit 0ec6b5ecd3
2 changed files with 95 additions and 134 deletions

View file

@ -590,19 +590,16 @@ static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
return res; \ return res; \
} while(0) } while(0)
#define ARG(x,y) \ #define ARG_ANY(n) \
x = interpret(what->y); \ v##n = interpret(what->a##n.p); \
if (x.type & T_RETURN) \ if (v##n.type & T_RETURN) \
return x; return v##n;
#define ARG(n,t) ARG_ANY(n) \
if (v##n.type != t) \
runtime("Argument %d of instruction %s must be of type %02x, got %02x", \
n, f_instruction_name(what->fi_code), t, v##n.type);
#define ONEARG ARG(v1, a1.p)
#define TWOARGS ARG(v1, a1.p) \
ARG(v2, a2.p)
#define TWOARGS_C TWOARGS \
if (v1.type != v2.type) \
runtime( "Can't operate with values of incompatible types" );
#define THREEARGS TWOARGS \
ARG(v3, a3.p)
#define ACCESS_RTE \ #define ACCESS_RTE \
do { if (!f_rte) runtime("No route to access"); } while (0) do { if (!f_rte) runtime("No route to access"); } while (0)
@ -640,61 +637,44 @@ interpret(struct f_inst *what)
switch(what->fi_code) { switch(what->fi_code) {
/* Binary operators */ /* Binary operators */
case FI_ADD: case FI_ADD:
TWOARGS_C; ARG(1,T_INT);
switch (res.type = v1.type) { ARG(2,T_INT);
case T_VOID: runtime( "Can't operate with values of type void" ); res.type = T_INT;
case T_INT: res.val.i = v1.val.i + v2.val.i; break; res.val.i = v1.val.i + v2.val.i;
default: runtime( "Usage of unknown type" );
}
break; break;
case FI_SUBTRACT: case FI_SUBTRACT:
TWOARGS_C; ARG(1,T_INT);
switch (res.type = v1.type) { ARG(2,T_INT);
case T_VOID: runtime( "Can't operate with values of type void" ); res.type = T_INT;
case T_INT: res.val.i = v1.val.i - v2.val.i; break; res.val.i = v1.val.i - v2.val.i;
default: runtime( "Usage of unknown type" );
}
break; break;
case FI_MULTIPLY: case FI_MULTIPLY:
TWOARGS_C; ARG(1,T_INT);
switch (res.type = v1.type) { ARG(2,T_INT);
case T_VOID: runtime( "Can't operate with values of type void" ); res.type = T_INT;
case T_INT: res.val.i = v1.val.i * v2.val.i; break; res.val.i = v1.val.i * v2.val.i;
default: runtime( "Usage of unknown type" );
}
break; break;
case FI_DIVIDE: case FI_DIVIDE:
TWOARGS_C; ARG(1,T_INT);
switch (res.type = v1.type) { ARG(2,T_INT);
case T_VOID: runtime( "Can't operate with values of type void" ); res.type = T_INT;
case T_INT: if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" ); if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
res.val.i = v1.val.i / v2.val.i; break; res.val.i = v1.val.i / v2.val.i;
default: runtime( "Usage of unknown type" );
}
break; break;
case FI_AND: case FI_AND:
case FI_OR: case FI_OR:
ARG(v1, a1.p); ARG(1,T_BOOL);
if (v1.type != T_BOOL)
runtime( "Can't do boolean operation on non-booleans" );
if (v1.val.i == (what->fi_code == FI_OR)) { if (v1.val.i == (what->fi_code == FI_OR)) {
res.type = T_BOOL; res.type = T_BOOL;
res.val.i = v1.val.i; res.val.i = v1.val.i;
break; } else {
ARG(2,T_BOOL);
res = v2;
} }
ARG(v2, a2.p);
if (v2.type != T_BOOL)
runtime( "Can't do boolean operation on non-booleans" );
res.type = T_BOOL;
res.val.i = v2.val.i;
break; break;
case FI_PAIR_CONSTRUCT: case FI_PAIR_CONSTRUCT:
TWOARGS; ARG(1,T_INT);
if ((v1.type != T_INT) || (v2.type != T_INT)) ARG(2,T_INT);
runtime( "Can't operate with value of non-integer type in pair constructor" );
u1 = v1.val.i; u1 = v1.val.i;
u2 = v2.val.i; u2 = v2.val.i;
if ((u1 > 0xFFFF) || (u2 > 0xFFFF)) if ((u1 > 0xFFFF) || (u2 > 0xFFFF))
@ -705,7 +685,8 @@ interpret(struct f_inst *what)
case FI_EC_CONSTRUCT: case FI_EC_CONSTRUCT:
{ {
TWOARGS; ARG_ANY(1);
ARG(2, T_INT);
int check, ipv4_used; int check, ipv4_used;
u32 key, val; u32 key, val;
@ -723,8 +704,6 @@ interpret(struct f_inst *what)
else else
runtime("Can't operate with key of non-integer/IPv4 type in EC constructor"); runtime("Can't operate with key of non-integer/IPv4 type in EC constructor");
if (v2.type != T_INT)
runtime("Can't operate with value of non-integer type in EC constructor");
val = v2.val.i; val = v2.val.i;
/* XXXX */ /* XXXX */
@ -751,10 +730,9 @@ interpret(struct f_inst *what)
case FI_LC_CONSTRUCT: case FI_LC_CONSTRUCT:
{ {
THREEARGS; ARG(1, T_INT);
ARG(2, T_INT);
if ((v1.type != T_INT) || (v2.type != T_INT) || (v3.type != T_INT)) ARG(3, T_INT);
runtime( "Can't operate with value of non-integer type in LC constructor" );
res.type = T_LC; res.type = T_LC;
res.val.lc = (lcomm) { v1.val.i, v2.val.i, v3.val.i }; res.val.lc = (lcomm) { v1.val.i, v2.val.i, v3.val.i };
@ -791,7 +769,8 @@ interpret(struct f_inst *what)
/* Relational operators */ /* Relational operators */
#define COMPARE(x) \ #define COMPARE(x) \
TWOARGS; \ ARG_ANY(1); \
ARG_ANY(2); \
i = val_compare(v1, v2); \ i = val_compare(v1, v2); \
if (i==CMP_ERROR) \ if (i==CMP_ERROR) \
runtime( "Can't compare values of incompatible types" ); \ runtime( "Can't compare values of incompatible types" ); \
@ -800,7 +779,8 @@ interpret(struct f_inst *what)
break; break;
#define SAME(x) \ #define SAME(x) \
TWOARGS; \ ARG_ANY(1); \
ARG_ANY(2); \
i = val_same(v1, v2); \ i = val_same(v1, v2); \
res.type = T_BOOL; \ res.type = T_BOOL; \
res.val.i = (x); \ res.val.i = (x); \
@ -812,15 +792,14 @@ interpret(struct f_inst *what)
case FI_LTE: COMPARE(i!=1); case FI_LTE: COMPARE(i!=1);
case FI_NOT: case FI_NOT:
ONEARG; ARG(1,T_BOOL);
if (v1.type != T_BOOL)
runtime( "Not applied to non-boolean" );
res = v1; res = v1;
res.val.i = !res.val.i; res.val.i = !res.val.i;
break; break;
case FI_MATCH: case FI_MATCH:
TWOARGS; ARG_ANY(1);
ARG_ANY(2);
res.type = T_BOOL; res.type = T_BOOL;
res.val.i = val_in_range(v1, v2); res.val.i = val_in_range(v1, v2);
if (res.val.i == CMP_ERROR) if (res.val.i == CMP_ERROR)
@ -829,7 +808,8 @@ interpret(struct f_inst *what)
break; break;
case FI_NOT_MATCH: case FI_NOT_MATCH:
TWOARGS; ARG_ANY(1);
ARG_ANY(2);
res.type = T_BOOL; res.type = T_BOOL;
res.val.i = val_in_range(v1, v2); res.val.i = val_in_range(v1, v2);
if (res.val.i == CMP_ERROR) if (res.val.i == CMP_ERROR)
@ -838,12 +818,12 @@ interpret(struct f_inst *what)
break; break;
case FI_DEFINED: case FI_DEFINED:
ONEARG; ARG_ANY(1);
res.type = T_BOOL; res.type = T_BOOL;
res.val.i = (v1.type != T_VOID) && !undef_value(v1); res.val.i = (v1.type != T_VOID) && !undef_value(v1);
break; break;
case FI_TYPE: case FI_TYPE:
ONEARG; ARG_ANY(1); /* There may be more types supporting this operation */
switch (v1.type) switch (v1.type)
{ {
case T_NET: case T_NET:
@ -855,16 +835,14 @@ interpret(struct f_inst *what)
} }
break; break;
case FI_IS_V4: case FI_IS_V4:
ONEARG; ARG(1, T_IP);
if (v1.type != T_IP)
runtime( "IP version check needs an IP address" );
res.type = T_BOOL; res.type = T_BOOL;
res.val.i = ipa_is_ip4(v1.val.ip); res.val.i = ipa_is_ip4(v1.val.ip);
break; break;
/* Set to indirect value, a1 = variable, a2 = value */ /* Set to indirect value, a1 = variable, a2 = value */
case FI_SET: case FI_SET:
ARG(v2, a2.p); ARG_ANY(2);
sym = what->a1.p; sym = what->a1.p;
vp = sym->def; vp = sym->def;
if ((sym->class != (SYM_VARIABLE | v2.type)) && (v2.type != T_VOID)) if ((sym->class != (SYM_VARIABLE | v2.type)) && (v2.type != T_VOID))
@ -899,24 +877,23 @@ interpret(struct f_inst *what)
res = * ((struct f_val *) what->a1.p); res = * ((struct f_val *) what->a1.p);
break; break;
case FI_PRINT: case FI_PRINT:
ONEARG; ARG_ANY(1);
val_format(v1, &f_buf); val_format(v1, &f_buf);
break; break;
case FI_CONDITION: /* ? has really strange error value, so we can implement if ... else nicely :-) */ case FI_CONDITION: /* ? has really strange error value, so we can implement if ... else nicely :-) */
ONEARG; ARG(1, T_BOOL);
if (v1.type != T_BOOL)
runtime( "If requires boolean expression" );
if (v1.val.i) { if (v1.val.i) {
ARG(res,a2.p); ARG_ANY(2);
res.val.i = 0; res.val.i = 0;
} else res.val.i = 1; } else
res.val.i = 1;
res.type = T_BOOL; res.type = T_BOOL;
break; break;
case FI_NOP: case FI_NOP:
debug( "No operation\n" ); debug( "No operation\n" );
break; break;
case FI_PRINT_AND_DIE: case FI_PRINT_AND_DIE:
ONEARG; ARG_ANY(1);
if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) && if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) &&
!(f_flags & FF_SILENT)) !(f_flags & FF_SILENT))
log_commit(*L_INFO, &f_buf); log_commit(*L_INFO, &f_buf);
@ -963,7 +940,7 @@ interpret(struct f_inst *what)
break; break;
case FI_RTA_SET: case FI_RTA_SET:
ACCESS_RTE; ACCESS_RTE;
ONEARG; ARG_ANY(1);
if (what->aux != v1.type) if (what->aux != v1.type)
runtime( "Attempt to set static attribute to incompatible type" ); runtime( "Attempt to set static attribute to incompatible type" );
@ -1109,7 +1086,7 @@ interpret(struct f_inst *what)
break; break;
case FI_EA_SET: case FI_EA_SET:
ACCESS_RTE; ACCESS_RTE;
ONEARG; ARG_ANY(1);
{ {
struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr)); struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
u16 code = what->a2.i; u16 code = what->a2.i;
@ -1218,16 +1195,14 @@ interpret(struct f_inst *what)
break; break;
case FI_PREF_SET: case FI_PREF_SET:
ACCESS_RTE; ACCESS_RTE;
ONEARG; ARG(1,T_INT);
if (v1.type != T_INT)
runtime( "Can't set preference to non-integer" );
if (v1.val.i > 0xFFFF) if (v1.val.i > 0xFFFF)
runtime( "Setting preference value out of bounds" ); runtime( "Setting preference value out of bounds" );
f_rte_cow(); f_rte_cow();
(*f_rte)->pref = v1.val.i; (*f_rte)->pref = v1.val.i;
break; break;
case FI_LENGTH: /* Get length of */ case FI_LENGTH: /* Get length of */
ONEARG; ARG_ANY(1);
res.type = T_INT; res.type = T_INT;
switch(v1.type) { switch(v1.type) {
case T_NET: res.val.i = net_pxlen(v1.val.net); break; case T_NET: res.val.i = net_pxlen(v1.val.net); break;
@ -1239,8 +1214,8 @@ interpret(struct f_inst *what)
} }
break; break;
case FI_SADR_SRC: /* Get SADR src prefix */ case FI_SADR_SRC: /* Get SADR src prefix */
ONEARG; ARG(1, T_NET);
if (v1.type != T_NET || !net_is_sadr(v1.val.net)) if (!net_is_sadr(v1.val.net))
runtime( "SADR expected" ); runtime( "SADR expected" );
{ {
@ -1253,8 +1228,8 @@ interpret(struct f_inst *what)
} }
break; break;
case FI_ROA_MAXLEN: /* Get ROA max prefix length */ case FI_ROA_MAXLEN: /* Get ROA max prefix length */
ONEARG; ARG(1, T_NET);
if (v1.type != T_NET || !net_is_roa(v1.val.net)) if (!net_is_roa(v1.val.net))
runtime( "ROA expected" ); runtime( "ROA expected" );
res.type = T_INT; res.type = T_INT;
@ -1263,8 +1238,8 @@ interpret(struct f_inst *what)
((net_addr_roa6 *) v1.val.net)->max_pxlen; ((net_addr_roa6 *) v1.val.net)->max_pxlen;
break; break;
case FI_ROA_ASN: /* Get ROA ASN */ case FI_ROA_ASN: /* Get ROA ASN */
ONEARG; ARG(1, T_NET);
if (v1.type != T_NET || !net_is_roa(v1.val.net)) if (!net_is_roa(v1.val.net))
runtime( "ROA expected" ); runtime( "ROA expected" );
res.type = T_INT; res.type = T_INT;
@ -1273,25 +1248,20 @@ interpret(struct f_inst *what)
((net_addr_roa6 *) v1.val.net)->asn; ((net_addr_roa6 *) v1.val.net)->asn;
break; break;
case FI_IP: /* Convert prefix to ... */ case FI_IP: /* Convert prefix to ... */
ONEARG; ARG(1, T_NET);
if (v1.type != T_NET)
runtime( "Prefix expected" );
res.type = T_IP; res.type = T_IP;
res.val.ip = net_prefix(v1.val.net); res.val.ip = net_prefix(v1.val.net);
break; break;
case FI_ROUTE_DISTINGUISHER: case FI_ROUTE_DISTINGUISHER:
ONEARG; ARG(1, T_NET);
if (v1.type != T_NET) res.type = T_IP;
runtime( "Prefix expected" );
if (!net_is_vpn(v1.val.net)) if (!net_is_vpn(v1.val.net))
runtime( "VPN address expected" ); runtime( "VPN address expected" );
res.type = T_RD; res.type = T_RD;
res.val.ec = net_rd(v1.val.net); res.val.ec = net_rd(v1.val.net);
break; break;
case FI_AS_PATH_FIRST: /* Get first ASN from AS PATH */ case FI_AS_PATH_FIRST: /* Get first ASN from AS PATH */
ONEARG; ARG(1, T_PATH);
if (v1.type != T_PATH)
runtime( "AS path expected" );
as = 0; as = 0;
as_path_get_first(v1.val.ad, &as); as_path_get_first(v1.val.ad, &as);
@ -1299,9 +1269,7 @@ interpret(struct f_inst *what)
res.val.i = as; res.val.i = as;
break; break;
case FI_AS_PATH_LAST: /* Get last ASN from AS PATH */ case FI_AS_PATH_LAST: /* Get last ASN from AS PATH */
ONEARG; ARG(1, T_PATH);
if (v1.type != T_PATH)
runtime( "AS path expected" );
as = 0; as = 0;
as_path_get_last(v1.val.ad, &as); as_path_get_last(v1.val.ad, &as);
@ -1309,20 +1277,18 @@ interpret(struct f_inst *what)
res.val.i = as; res.val.i = as;
break; break;
case FI_AS_PATH_LAST_NAG: /* Get last ASN from non-aggregated part of AS PATH */ case FI_AS_PATH_LAST_NAG: /* Get last ASN from non-aggregated part of AS PATH */
ONEARG; ARG(1, T_PATH);
if (v1.type != T_PATH)
runtime( "AS path expected" );
res.type = T_INT; res.type = T_INT;
res.val.i = as_path_get_last_nonaggregated(v1.val.ad); res.val.i = as_path_get_last_nonaggregated(v1.val.ad);
break; break;
case FI_RETURN: case FI_RETURN:
ONEARG; ARG_ANY(1);
res = v1; res = v1;
res.type |= T_RETURN; res.type |= T_RETURN;
return res; return res;
case FI_CALL: /* CALL: this is special: if T_RETURN and returning some value, mask it out */ case FI_CALL: /* CALL: this is special: if T_RETURN and returning some value, mask it out */
ONEARG; ARG_ANY(1);
res = interpret(what->a2.p); res = interpret(what->a2.p);
if (res.type == T_RETURN) if (res.type == T_RETURN)
return res; return res;
@ -1333,7 +1299,7 @@ interpret(struct f_inst *what)
((struct f_val *) sym->def)->type = T_VOID; ((struct f_val *) sym->def)->type = T_VOID;
break; break;
case FI_SWITCH: case FI_SWITCH:
ONEARG; ARG_ANY(1);
{ {
struct f_tree *t = find_tree(what->a2.p, v1); struct f_tree *t = find_tree(what->a2.p, v1);
if (!t) { if (!t) {
@ -1352,11 +1318,8 @@ interpret(struct f_inst *what)
} }
break; break;
case FI_IP_MASK: /* IP.MASK(val) */ case FI_IP_MASK: /* IP.MASK(val) */
TWOARGS; ARG(1, T_IP);
if (v2.type != T_INT) ARG(2, T_INT);
runtime( "Integer expected");
if (v1.type != T_IP)
runtime( "You can mask only IP addresses" );
res.type = T_IP; res.type = T_IP;
res.val.ip = ipa_is_ip4(v1.val.ip) ? res.val.ip = ipa_is_ip4(v1.val.ip) ?
@ -1369,18 +1332,16 @@ interpret(struct f_inst *what)
res.val.ad = adata_empty(f_pool, 0); res.val.ad = adata_empty(f_pool, 0);
break; break;
case FI_PATH_PREPEND: /* Path prepend */ case FI_PATH_PREPEND: /* Path prepend */
TWOARGS; ARG(1, T_PATH);
if (v1.type != T_PATH) ARG(2, T_INT);
runtime("Can't prepend to non-path");
if (v2.type != T_INT)
runtime("Can't prepend non-integer");
res.type = T_PATH; res.type = T_PATH;
res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i); res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
break; break;
case FI_CLIST_ADD_DEL: /* (Extended) Community list add or delete */ case FI_CLIST_ADD_DEL: /* (Extended) Community list add or delete */
TWOARGS; ARG_ANY(1);
ARG_ANY(2);
if (v1.type == T_PATH) if (v1.type == T_PATH)
{ {
struct f_tree *set = NULL; struct f_tree *set = NULL;
@ -1548,9 +1509,8 @@ interpret(struct f_inst *what)
case FI_ROA_CHECK: /* ROA Check */ case FI_ROA_CHECK: /* ROA Check */
if (what->arg1) if (what->arg1)
{ {
TWOARGS; ARG(1, T_NET);
if ((v1.type != T_NET) || (v2.type != T_INT)) ARG(2, T_INT);
runtime("Invalid argument to roa_check()");
as = v2.val.i; as = v2.val.i;
} }
@ -1586,17 +1546,14 @@ interpret(struct f_inst *what)
break; break;
case FI_FORMAT: /* Format */ case FI_FORMAT: /* Format */
ONEARG; ARG_ANY(1);
res.type = T_STRING; res.type = T_STRING;
res.val.s = val_format_str(v1); res.val.s = val_format_str(v1);
break; break;
case FI_ASSERT: /* Birdtest Assert */ case FI_ASSERT: /* Birdtest Assert */
ONEARG; ARG(1, T_BOOL);
if (v1.type != T_BOOL)
runtime("Should be boolean value");
res.type = v1.type; res.type = v1.type;
res.val = v1.val; res.val = v1.val;
@ -1611,13 +1568,15 @@ interpret(struct f_inst *what)
} }
#undef ARG #undef ARG
#define ARG(x,y) \ #undef ARG_ANY
if (!i_same(f1->y, f2->y)) \
#define ARG(n) \
if (!i_same(f1->a##n.p, f2->a##n.p)) \
return 0; return 0;
#define ONEARG ARG(v1, a1.p) #define ONEARG ARG(1);
#define TWOARGS ARG(v1, a1.p) \ #define TWOARGS ONEARG; ARG(2);
ARG(v2, a2.p) #define THREEARGS TWOARGS; ARG(3);
#define A2_SAME if (f1->a2.i != f2->a2.i) return 0; #define A2_SAME if (f1->a2.i != f2->a2.i) return 0;
@ -1665,7 +1624,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
break; break;
case FI_SET: case FI_SET:
ARG(v2, a2.p); ARG(2);
{ {
struct symbol *s1, *s2; struct symbol *s1, *s2;
s1 = f1->a1.p; s1 = f1->a1.p;

View file

@ -81,6 +81,8 @@ FI__LIST
FI__MAX, FI__MAX,
} PACKED; } PACKED;
const char *f_instruction_name(enum f_instruction_code fi);
struct f_inst { /* Instruction */ struct f_inst { /* Instruction */
struct f_inst *next; /* Structure is 16 bytes, anyway */ struct f_inst *next; /* Structure is 16 bytes, anyway */
enum f_instruction_code fi_code; enum f_instruction_code fi_code;