1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
"""
Hooks for validating CPython extension source code
"""
def get_types(strfmt):
"""
Generate a list of C type names from a PyArg_ParseTuple format string
Compare to Python/getargs.c:vgetargs1
"""
result = []
i = 0
while i < len(strfmt):
c = strfmt[i]
simple = {'i':'int',
's':'char *'}
if c in simple:
result.append(simple[c] + ' *')
if c in [':', ';']:
break
i += 1
return result
class CExtensionError(Exception):
# Base class for errors discovered by static analysis in C extension code
def __init__(self, location):
self.location = location
def __str__(self):
return '%s:%s: %s' % (self.location.file,
self.location.line,
self._get_desc())
def _get_desc(self):
raise NotImplementedError
class WrongNumberOfVars(CExtensionError):
def __init__(self, location, exp_types, actual_types):
CExtensionError.__init__(self, location)
self.exp_types = exp_types
self.actual_types = actual_types
class NotEnoughVars(WrongNumberOfVars):
def _get_desc(self):
return 'Not enough arguments: expected %i (%s), but got %i (%s)' % (
len(self.exp_types),
self.exp_types,
len(self.actual_types),
self.actual_types)
class TooManyVars(WrongNumberOfVars):
def _get_desc(self):
return 'Too many arguments: expected %i (%s), but got %i (%s)' % (
len(self.exp_types),
self.exp_types,
len(self.actual_types),
self.actual_types)
class MismatchingType(CExtensionError):
def __init__(self, location, arg_num, exp_type, actual_type):
super(self.__class__, self).__init__(location)
self.arg_num = arg_num
self.exp_type = exp_type
self.actual_type = actual_type
def _get_desc(self):
return 'Mismatching type of argument %i: expected "%s" but got "%s"' % (
self.arg_num,
self.exp_type,
self.actual_type)
def validate_types(location, format_string, actual_types):
try:
exp_types = get_types(format_string)
if len(actual_types) < len(exp_types):
raise NotEnoughVars(location, actual_types, exp_types)
if len(actual_types) > len(exp_types):
raise TooManyVars(location, actual_types, exp_types)
for i, (exp, actual) in enumerate(zip(exp_types, actual_types)):
if exp != actual:
raise MismatchingType(location, i+1, exp, actual)
except CExtensionError, err:
print err
|