diff options
-rw-r--r-- | pyarg-parsetuple.cocci | 130 | ||||
-rw-r--r-- | validate.py | 47 |
2 files changed, 79 insertions, 98 deletions
diff --git a/pyarg-parsetuple.cocci b/pyarg-parsetuple.cocci index c0d9595..dd31702 100644 --- a/pyarg-parsetuple.cocci +++ b/pyarg-parsetuple.cocci @@ -16,123 +16,97 @@ @initialize:python@ """ Analyze format strings passed to variadic function, compare to vararg types actually passed - -FIXME: generalize this to arbitrary number of varargs; how to express this in SmPL? """ import sys sys.path.append('.') -from validate import validate_types +from validate import validate_type num_errors = 0 -@ check_PyArg_ParseTuple_1 @ +@ check_PyArg_ParseTuple @ position pos; expression args; expression fmt; -type t1; -t1 e1; +expression list[len_E] E; +expression list[len_F] F; +type t; +t e; @@ -PyArg_ParseTuple@pos(args, fmt, e1) +PyArg_ParseTuple@pos(args, fmt, E, e, F) @script:python@ -pos << check_PyArg_ParseTuple_1.pos; -fmt << check_PyArg_ParseTuple_1.fmt; -t1 << check_PyArg_ParseTuple_1.t1; +pos << check_PyArg_ParseTuple.pos; +fmt << check_PyArg_ParseTuple.fmt; +len_E << check_PyArg_ParseTuple.len_E; +len_F << check_PyArg_ParseTuple.len_F; +t << check_PyArg_ParseTuple.t; @@ +num_errors += validate_type(pos[0], + fmt.expr, + int(len_E), + int(len_E) + 1 + int(len_F), + t) -# For some reason, locations are coming as a 1-tuple containing a Location (from -# coccilibs.elems), rather than the location itself -# Hence we use p1[0], not p1 -num_errors += validate_types(pos[0], fmt.expr, [t1]) +# likewise for PyArg_Parse etc: -@ check_PyArg_ParseTuple_2 @ +@ check_PyArg_Parse @ position pos; expression args; expression fmt; -type t1; -t1 e1; -type t2; -t2 e2; +expression list[len_E] E; +expression list[len_F] F; +type t; +t e; @@ -PyArg_ParseTuple(args@pos, fmt, e1, e2) +PyArg_Parse@pos(args, fmt, E, e, F) @script:python@ -fmt << check_PyArg_ParseTuple_2.fmt; -pos << check_PyArg_ParseTuple_2.pos; -t1 << check_PyArg_ParseTuple_2.t1; -t2 << check_PyArg_ParseTuple_2.t2; +pos << check_PyArg_Parse.pos; +fmt << check_PyArg_Parse.fmt; +len_E << check_PyArg_Parse.len_E; +len_F << check_PyArg_Parse.len_F; +t << check_PyArg_Parse.t; @@ -num_errors += validate_types(pos[0], fmt.expr, [t1, t2]) +num_errors += validate_type(pos[0], + fmt.expr, + int(len_E), + int(len_E) + 1 + int(len_F), + t) -@ check_PyArg_ParseTuple_3 @ +@ check_PyArg_ParseTupleAndKeywords @ position pos; expression args; +expression keywords; expression fmt; -type t1; t1 e1; -type t2; t2 e2; -type t3; t3 e3; -@@ - -PyArg_ParseTuple(args@pos, fmt, e1, e2, e3) - -@script:python@ -pos << check_PyArg_ParseTuple_3.pos; -fmt << check_PyArg_ParseTuple_3.fmt; -pos << check_PyArg_ParseTuple_3.pos; -t1 << check_PyArg_ParseTuple_3.t1; -t2 << check_PyArg_ParseTuple_3.t2; -t3 << check_PyArg_ParseTuple_3.t3; +expression argnames; +expression list[len_E] E; +expression list[len_F] F; +type t; +t e; @@ -num_errors += validate_types(pos[0], fmt.expr, [t1, t2, t3]) - -# and so on... need to find a general way of doing this, rather than repeating for 4, 5, 6... -# likewise for PyArg_Parse: +PyArg_ParseTupleAndKeywords@pos(args, keywords, fmt, argnames, E, e, F) -@ check_PyArg_Parse_1 @ -position pos; -expression args; -expression fmt; -type t1; -t1 e1; -@@ - -PyArg_Parse@pos(args, fmt, e1) @script:python@ -pos << check_PyArg_Parse_1.pos; -args << check_PyArg_Parse_1.args; -fmt << check_PyArg_Parse_1.fmt; -pos << check_PyArg_Parse_1.pos; -t1 << check_PyArg_Parse_1.t1; +pos << check_PyArg_ParseTupleAndKeywords.pos; +fmt << check_PyArg_ParseTupleAndKeywords.fmt; +len_E << check_PyArg_ParseTupleAndKeywords.len_E; +len_F << check_PyArg_ParseTupleAndKeywords.len_F; +t << check_PyArg_ParseTupleAndKeywords.t; @@ -num_errors += validate_types(pos[0], fmt.expr, [t1]) - -# again, for all N -# similarly for PyArg_ParseTupleAndKeywords: +num_errors += validate_type(pos[0], + fmt.expr, + int(len_E), + int(len_E) + 1 + int(len_F), + t) -@ check_PyArg_ParseTupleAndKeywords_1 @ -position pos; -expression args, kw, fmt, keywords; -type t1; -t1 e1; -@@ -PyArg_ParseTupleAndKeywords@pos(args, kw, fmt, keywords, e1) -@script:python@ -pos << check_PyArg_Parse_1.pos; -args << check_PyArg_Parse_1.args; -fmt << check_PyArg_Parse_1.fmt; -pos << check_PyArg_Parse_1.pos; -t1 << check_PyArg_Parse_1.t1; -@@ -num_errors += validate_types(pos[0], fmt.expr, [t1]) -# etc @script:python @ @@ diff --git a/validate.py b/validate.py index 786d7c0..6d50921 100644 --- a/validate.py +++ b/validate.py @@ -141,28 +141,26 @@ def get_types(location, strfmt): class WrongNumberOfVars(FormatStringError): - def __init__(self, location, format_string, exp_types, actual_types): + def __init__(self, location, format_string, exp_types, num_args): FormatStringError.__init__(self, location, format_string) self.exp_types = exp_types - self.actual_types = actual_types + self.num_args = num_args class NotEnoughVars(WrongNumberOfVars): def _get_desc(self): - return 'Not enough arguments in "%s" : expected %i (%s), but got %i (%s)' % ( + return 'Not enough arguments in "%s" : expected %i (%s), but got %i' % ( self.format_string, len(self.exp_types), self.exp_types, - len(self.actual_types), - self.actual_types) + self.num_args) class TooManyVars(WrongNumberOfVars): def _get_desc(self): - return 'Too many arguments in "%s": expected %i (%s), but got %i (%s)' % ( + return 'Too many arguments in "%s": expected %i (%s), but got %i' % ( self.format_string, len(self.exp_types), self.exp_types, - len(self.actual_types), - self.actual_types) + self.num_args) class MismatchingType(FormatStringError): def __init__(self, location, format_string, arg_num, exp_type, actual_type): @@ -194,24 +192,33 @@ def type_equality(t1, t2): return False -def validate_types(location, format_string, actual_types): +def validate_type(location, format_string, index, actual_num_args, actual_type): if False: - print 'validate_types(%s, %s, %s)' % ( - repr(location), repr(format_string), repr(actual_types)) + print 'validate_types(%s, %s, %s, %s, %s)' % ( + repr(location), + repr(format_string), + repr(index), + repr(actual_num_args), + repr(actual_type)) + try: exp_types = get_types(location, format_string[1:-1]) # strip leading and trailing " chars - if len(actual_types) < len(exp_types): - raise NotEnoughVars(location, format_string, exp_types, actual_types) - if len(actual_types) > len(exp_types): - raise TooManyVars(location, format_string, exp_types, actual_types) - for i, (exp, actual) in enumerate(zip(exp_types, actual_types)): - if not type_equality(exp, actual): - raise MismatchingType(location, format_string, i+1, exp, actual) + if actual_num_args < len(exp_types): + raise NotEnoughVars(location, format_string, exp_types, actual_num_args) + if actual_num_args > len(exp_types): + raise TooManyVars(location, format_string, exp_types, actual_num_args) + exp_type = exp_types[index] + if not type_equality(exp_type, actual_type): + raise MismatchingType(location, format_string, index+1, exp_type, actual_type) except CExtensionError, err: print err if False: - print 'validate_types(%s, %s, %s)' % ( - repr(location), repr(format_string), repr(actual_types)) + print 'validate_types(%s, %s, %s, %s, %s)' % ( + repr(location), + repr(format_string), + repr(index), + repr(actual_num_args), + repr(actual_type)) return 1 return 0 |