static void check_function(stnode_t *st_node) { df_func_def_t *funcdef; GSList *params; guint iparam; guint nparams; funcdef = sttype_function_funcdef(st_node); params = sttype_function_params(st_node); nparams = g_slist_length(params); if (nparams < funcdef->min_nargs) { dfilter_fail("Function %s needs at least %u arguments.", funcdef->name, funcdef->min_nargs); THROW(TypeError); } else if (nparams > funcdef->max_nargs) { dfilter_fail("Function %s can only accept %u arguments.", funcdef->name, funcdef->max_nargs); THROW(TypeError); } iparam = 0; while (params) { params->data = check_param_entity(params->data); funcdef->semcheck_param_function(iparam, params->data); params = params->next; iparam++; } }
/* returns register number that the functions's result will be in. */ static int dfw_append_function(dfwork_t *dfw, stnode_t *node, dfvm_value_t **p_jmp) { GSList *params; int i, num_params, reg; dfvm_value_t **jmps; dfvm_insn_t *insn; dfvm_value_t *val1, *val2, *val; params = sttype_function_params(node); num_params = g_slist_length(params); /* Array to hold the instructions that need to jump to * an instruction if they fail. */ jmps = (dfvm_value_t **)g_malloc(num_params * sizeof(dfvm_value_t*)); /* Create the new DFVM instruction */ insn = dfvm_insn_new(CALL_FUNCTION); val1 = dfvm_value_new(FUNCTION_DEF); val1->value.funcdef = sttype_function_funcdef(node); insn->arg1 = val1; val2 = dfvm_value_new(REGISTER); val2->value.numeric = dfw->next_register++; insn->arg2 = val2; insn->arg3 = NULL; insn->arg4 = NULL; i = 0; while (params) { jmps[i] = NULL; reg = gen_entity(dfw, (stnode_t *)params->data, &jmps[i]); val = dfvm_value_new(REGISTER); val->value.numeric = reg; switch(i) { case 0: insn->arg3 = val; break; case 1: insn->arg4 = val; break; default: g_assert_not_reached(); } params = params->next; i++; } dfw_append_insn(dfw, insn); /* If any of our parameters failed, send them to * our own failure instruction. This *has* to be done * after we caled dfw_append_insn above so that * we know what the next DFVM insruction is, via * dfw->next_insn_id */ for (i = 0; i < num_params; i++) { if (jmps[i]) { jmps[i]->value.numeric = dfw->next_insn_id; } } /* We need another instruction to jump to another exit * place, if the call() of our function failed for some reaosn */ insn = dfvm_insn_new(IF_FALSE_GOTO); g_assert(p_jmp); *p_jmp = dfvm_value_new(INSN_NUMBER); insn->arg1 = *p_jmp; dfw_append_insn(dfw, insn); g_free(jmps); return val2->value.numeric; }
/* If the LHS of a relation test is a FUNCTION, run some checks * and possibly some modifications of syntax tree nodes. */ static void check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func, gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; sttype_id_t type2; header_field_info *hfinfo2; ftenum_t ftype1, ftype2; fvalue_t *fvalue; char *s; drange_node *rn; df_func_def_t *funcdef; df_func_def_t *funcdef2; GSList *params; check_function(st_arg1); type2 = stnode_type_id(st_arg2); funcdef = sttype_function_funcdef(st_arg1); ftype1 = funcdef->retval_ftype; params = sttype_function_params(st_arg1); DebugLog((" 5 check_relation_LHS_FUNCTION(%s)\n", relation_string)); if (!can_func(ftype1)) { dfilter_fail("Function %s (type=%s) cannot participate in '%s' comparison.", funcdef->name, ftype_pretty_name(ftype1), relation_string); THROW(TypeError); } if (type2 == STTYPE_FIELD) { hfinfo2 = stnode_data(st_arg2); ftype2 = hfinfo2->type; if (!compatible_ftypes(ftype1, ftype2)) { dfilter_fail("Function %s and %s are not of compatible types.", funcdef->name, hfinfo2->abbrev); THROW(TypeError); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { dfilter_fail("%s (type=%s) cannot participate in specified comparison.", hfinfo2->abbrev, ftype_pretty_name(ftype2)); THROW(TypeError); } } else if (type2 == STTYPE_STRING) { s = stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = fvalue_from_string(FT_PCRE, s, dfilter_fail); } else { fvalue = fvalue_from_string(ftype1, s, dfilter_fail); } if (!fvalue) { THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_UNPARSED) { s = stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = fvalue_from_unparsed(FT_PCRE, s, FALSE, dfilter_fail); } else { fvalue = fvalue_from_unparsed(ftype1, s, allow_partial_value, dfilter_fail); } if (!fvalue) { THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_RANGE) { check_drange_sanity(st_arg2); if (!is_bytes_type(ftype1)) { if (!ftype_can_slice(ftype1)) { dfilter_fail("Function \"%s\" is a %s and cannot be converted into a sequence of bytes.", funcdef->name, ftype_pretty_name(ftype1)); THROW(TypeError); } /* Convert entire field to bytes */ new_st = stnode_new(STTYPE_RANGE, NULL); rn = drange_node_new(); drange_node_set_start_offset(rn, 0); drange_node_set_to_the_end(rn); /* st_arg1 is freed in this step */ sttype_range_set1(new_st, st_arg1, rn); sttype_test_set2_args(st_node, new_st, st_arg2); } } else if (type2 == STTYPE_FUNCTION) { funcdef2 = sttype_function_funcdef(st_arg2); ftype2 = funcdef2->retval_ftype; if (!compatible_ftypes(ftype1, ftype2)) { dfilter_fail("Return values of function %s (type=%s) and function %s (type=%s) are not of compatible types.", funcdef->name, ftype_pretty_name(ftype1), funcdef2->name, ftype_pretty_name(ftype2)); THROW(TypeError); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { dfilter_fail("Return value of %s (type=%s) cannot participate in specified comparison.", funcdef2->name, ftype_pretty_name(ftype2)); THROW(TypeError); } check_function(st_arg2); } else { g_assert_not_reached(); } }
/* If the LHS of a relation test is a FUNCTION, run some checks * and possibly some modifications of syntax tree nodes. */ static void check_relation_LHS_FUNCTION(dfwork_t *dfw, const char *relation_string, FtypeCanFunc can_func, gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; sttype_id_t type2; header_field_info *hfinfo2; ftenum_t ftype1, ftype2; fvalue_t *fvalue; char *s; df_func_def_t *funcdef; df_func_def_t *funcdef2; /* GSList *params; */ check_function(dfw, st_arg1); type2 = stnode_type_id(st_arg2); funcdef = sttype_function_funcdef(st_arg1); ftype1 = funcdef->retval_ftype; /* params = */sttype_function_params(st_arg1); /* XXX: is this done for the side-effect ? */ DebugLog((" 5 check_relation_LHS_FUNCTION(%s)\n", relation_string)); if (!can_func(ftype1)) { dfilter_fail(dfw, "Function %s (type=%s) cannot participate in '%s' comparison.", funcdef->name, ftype_pretty_name(ftype1), relation_string); THROW(TypeError); } if (type2 == STTYPE_FIELD) { hfinfo2 = (header_field_info*)stnode_data(st_arg2); ftype2 = hfinfo2->type; if (!compatible_ftypes(ftype1, ftype2)) { dfilter_fail(dfw, "Function %s and %s are not of compatible types.", funcdef->name, hfinfo2->abbrev); THROW(TypeError); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { dfilter_fail(dfw, "%s (type=%s) cannot participate in specified comparison.", hfinfo2->abbrev, ftype_pretty_name(ftype2)); THROW(TypeError); } } else if (type2 == STTYPE_STRING) { s = (char*)stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = dfilter_fvalue_from_string(dfw, FT_PCRE, s); } else { fvalue = dfilter_fvalue_from_string(dfw, ftype1, s); } if (!fvalue) { THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_UNPARSED) { s = (char*)stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = dfilter_fvalue_from_unparsed(dfw, FT_PCRE, s, FALSE); } else { fvalue = dfilter_fvalue_from_unparsed(dfw, ftype1, s, allow_partial_value); } if (!fvalue) { THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_RANGE) { check_drange_sanity(dfw, st_arg2); if (!is_bytes_type(ftype1)) { if (!ftype_can_slice(ftype1)) { dfilter_fail(dfw, "Function \"%s\" is a %s and cannot be converted into a sequence of bytes.", funcdef->name, ftype_pretty_name(ftype1)); THROW(TypeError); } /* Convert function result to bytes */ new_st = convert_to_bytes(st_arg1); sttype_test_set2_args(st_node, new_st, st_arg2); } } else if (type2 == STTYPE_FUNCTION) { funcdef2 = sttype_function_funcdef(st_arg2); ftype2 = funcdef2->retval_ftype; if (!compatible_ftypes(ftype1, ftype2)) { dfilter_fail(dfw, "Return values of function %s (type=%s) and function %s (type=%s) are not of compatible types.", funcdef->name, ftype_pretty_name(ftype1), funcdef2->name, ftype_pretty_name(ftype2)); THROW(TypeError); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { dfilter_fail(dfw, "Return value of %s (type=%s) cannot participate in specified comparison.", funcdef2->name, ftype_pretty_name(ftype2)); THROW(TypeError); } check_function(dfw, st_arg2); } else if (type2 == STTYPE_SET) { dfilter_fail(dfw, "Only a field may be tested for membership in a set."); THROW(TypeError); } else { g_assert_not_reached(); } }