summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pyarg-parsetuple.cocci130
-rw-r--r--validate.py47
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