From yami (bug 3361):

Try to resolve a crash issue when having a function on the RHS
of a filter test which does not return the same type as the LHS.

svn path=/trunk/; revision=28550
This commit is contained in:
Stig Bjørlykke 2009-05-31 19:46:31 +00:00
parent 1f8c72ff25
commit bcf8cf90e1
1 changed files with 146 additions and 24 deletions

View File

@ -53,6 +53,9 @@
static void
semcheck(stnode_t *st_node);
static stnode_t*
check_param_entity(stnode_t *st_node);
typedef gboolean (*FtypeCanFunc)(enum ftenum);
/* Compares to ftenum_t's and decides if they're
@ -421,6 +424,37 @@ check_drange_sanity(stnode_t *st)
}
}
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++;
}
}
/* If the LHS of a relation test is a FIELD, run some checks
* and possibly some modifications of syntax tree nodes. */
static void
@ -431,6 +465,7 @@ check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func,
stnode_t *new_st;
sttype_id_t type1, type2;
header_field_info *hfinfo1, *hfinfo2;
df_func_def_t *funcdef;
ftenum_t ftype1, ftype2;
fvalue_t *fvalue;
char *s;
@ -530,6 +565,25 @@ check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func,
sttype_test_set2_args(st_node, new_st, st_arg2);
}
}
else if (type2 == STTYPE_FUNCTION) {
funcdef = sttype_function_funcdef(st_arg2);
ftype2 = funcdef->retval_ftype;
if (!compatible_ftypes(ftype1, ftype2)) {
dfilter_fail("%s (type=%s) and return value of %s() (type=%s) are not of compatible types.",
hfinfo1->abbrev, ftype_pretty_name(ftype1),
funcdef->name, ftype_pretty_name(ftype2));
THROW(TypeError);
}
if (!can_func(ftype2)) {
dfilter_fail("return value of %s() (type=%s) cannot participate in specified comparison.",
funcdef->name, ftype_pretty_name(ftype2));
THROW(TypeError);
}
check_function(st_arg2);
}
else {
g_assert_not_reached();
}
@ -544,6 +598,7 @@ check_relation_LHS_STRING(const char* relation_string,
stnode_t *new_st;
sttype_id_t type1, type2;
header_field_info *hfinfo2;
df_func_def_t *funcdef;
ftenum_t ftype2;
fvalue_t *fvalue;
char *s;
@ -596,6 +651,29 @@ check_relation_LHS_STRING(const char* relation_string,
sttype_test_set2_args(st_node, new_st, st_arg2);
stnode_free(st_arg1);
}
else if (type2 == STTYPE_FUNCTION) {
funcdef = sttype_function_funcdef(st_arg2);
ftype2 = funcdef->retval_ftype;
if (!can_func(ftype2)) {
dfilter_fail("Return value of function %s (type=%s) cannot participate in '%s' comparison.",
funcdef->name, ftype_pretty_name(ftype2),
relation_string);
THROW(TypeError);
}
s = stnode_data(st_arg1);
fvalue = fvalue_from_string(ftype2, s, dfilter_fail);
if (!fvalue) {
THROW(TypeError);
}
check_function(st_arg2);
new_st = stnode_new(STTYPE_FVALUE, fvalue);
sttype_test_set2_args(st_node, new_st, st_arg2);
stnode_free(st_arg1);
}
else {
g_assert_not_reached();
}
@ -610,6 +688,7 @@ check_relation_LHS_UNPARSED(const char* relation_string,
stnode_t *new_st;
sttype_id_t type1, type2;
header_field_info *hfinfo2;
df_func_def_t *funcdef;
ftenum_t ftype2;
fvalue_t *fvalue;
char *s;
@ -662,6 +741,29 @@ check_relation_LHS_UNPARSED(const char* relation_string,
sttype_test_set2_args(st_node, new_st, st_arg2);
stnode_free(st_arg1);
}
else if (type2 == STTYPE_FUNCTION) {
funcdef = sttype_function_funcdef(st_arg2);
ftype2 = funcdef->retval_ftype;
if (!can_func(ftype2)) {
dfilter_fail("return value of function %s() (type=%s) cannot participate in '%s' comparison.",
funcdef->name, ftype_pretty_name(ftype2), relation_string);
THROW(TypeError);
}
s = stnode_data(st_arg1);
fvalue = fvalue_from_unparsed(ftype2, s, allow_partial_value, dfilter_fail);
if (!fvalue) {
THROW(TypeError);
}
check_function(st_arg2);
new_st = stnode_new(STTYPE_FVALUE, fvalue);
sttype_test_set2_args(st_node, new_st, st_arg2);
stnode_free(st_arg1);
}
else {
g_assert_not_reached();
}
@ -676,6 +778,7 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_,
stnode_t *new_st;
sttype_id_t type1, type2;
header_field_info *hfinfo1, *hfinfo2;
df_func_def_t *funcdef;
ftenum_t ftype1, ftype2;
fvalue_t *fvalue;
char *s;
@ -759,6 +862,23 @@ check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_,
DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_RANGE)\n"));
check_drange_sanity(st_arg2);
}
else if (type2 == STTYPE_FUNCTION) {
funcdef = sttype_function_funcdef(st_arg2);
ftype2 = funcdef->retval_ftype;
if (!is_bytes_type(ftype2)) {
if (!ftype_can_slice(ftype2)) {
dfilter_fail("Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.",
funcdef->name,
ftype_pretty_name(ftype2));
THROW(TypeError);
}
/* XXX should I add a new drange node? */
}
check_function(st_arg2);
}
else {
g_assert_not_reached();
}
@ -803,36 +923,18 @@ check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func,
ftenum_t ftype1, ftype2;
fvalue_t *fvalue;
char *s;
int param_i;
drange_node *rn;
df_func_def_t *funcdef;
guint num_params;
GSList *params;
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);
funcdef = sttype_function_funcdef(st_arg1);
ftype1 = funcdef->retval_ftype;
params = sttype_function_params(st_arg1);
num_params = g_slist_length(params);
if (num_params < funcdef->min_nargs) {
dfilter_fail("Function %s needs at least %u arguments.",
funcdef->name, funcdef->min_nargs);
THROW(TypeError);
}
else if (num_params > funcdef->max_nargs) {
dfilter_fail("Function %s can only accept %u arguments.",
funcdef->name, funcdef->max_nargs);
THROW(TypeError);
}
param_i = 0;
while (params) {
params->data = check_param_entity(params->data);
funcdef->semcheck_param_function(param_i, params->data);
params = params->next;
}
params = sttype_function_params(st_arg1);
DebugLog((" 5 check_relation_LHS_FUNCTION(%s)\n", relation_string));
@ -914,6 +1016,26 @@ check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func,
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();
}