Move the sources to trunk
[opencv] / utils / search_leaks.py
1 #!/usr/bin/env python
2 usage = """
3 Usage: search_leaks.py <directory> > log.txt
4
5 This simple script parses a source directory
6 of one of OpenCV source modules
7 and tries to find cvAlloc, cvCreateMat etc.
8 without corresponding cvFree, cvReleaseMat etc. 
9 Information about the suspicious places
10 is printed to standard output.
11 """
12
13 import sys, os, re, glob
14
15 allocfuncs = [ ('cvAlloc', 'cvFree'),
16                ('cvCreateMatND', 'cvReleaseMatND'),
17                ('cvCreateMat', 'cvReleaseMat'),
18                ('cvCreateImage', 'cvReleaseImage'),
19                ('cvCreateHist', 'cvReleaseHist'),
20                ('cvCreateSparseMat', 'cvReleaseSparseMat'),
21                ('cvCreateMemStorage', 'cvReleaseMemStorage'),
22                ('cvCreateChildMemStorage', 'cvReleaseMemStorage'),
23                ('icvIPPFilterInit', 'cvFree'),
24                ('icvFilterInitAlloc', 'icvFilterFree'),
25                ('icvSobelInitAlloc', 'icvFilterFree'),
26                ('icvScharrInitAlloc', 'icvFilterFree'),
27                ('icvLaplaceInitAlloc', 'icvFilterFree'),
28                ('icvSmoothInitAlloc', 'icvSmoothFree'),
29                ('icvMorphInitAlloc', 'icvMorphFree'),]
30
31 if len(sys.argv) != 2:
32     print usage
33
34 leaks = 0
35 falsealarms = 0
36
37 glob_expr = sys.argv[1] + '/*.c*'
38 for srcname in glob.glob(glob_expr):
39     f = open(srcname,'r')
40     lineno = 0
41     allocdict = {}
42     fname = ""
43     for l in f.xreadlines():
44         lineno += 1
45         if len(l)>1 and l[0] not in " \t/":
46             if l[0] == "}":
47                 # analyze the allocation map
48                 leaks0 = leaks
49                 for (name,p) in allocdict.items():
50                     if p[1] > 0:
51                         print "%s(%d): function %s: %s is not deallocated" % \
52                             (srcname, lineno, fname, name)
53                         leaks += 1
54                 if fname == "cvAlloc" or re.findall( "^i?cv(Create)|(Read)|(Clone)", fname ):
55                     if leaks > leaks0:
56                         print "%s(%d): function %s: some of leaks are probably false alarms" % \
57                             (srcname, lineno, fname)
58                         falsealarms += leaks - leaks0
59                 fname = ""
60                 allocdict = {}
61                 #print "%s(%d): clearing map..." % (srcname, lineno)
62             else:
63                 m = re.findall( r'(\bi?cv\w+)\(', l )
64                 if m and m[0]:
65                     fname = m[0]
66                     allocdict = {}
67                     #print "%s(%d): clearing map..." % (srcname, lineno)
68         # that's a small speedup that might fail
69         # if create/release naming convention is not used for some structure
70         elif l.find( 'Alloc') >= 0 or l.find('Create') >= 0 or l.find('Init') >= 0:
71             for i in allocfuncs:
72                 m = re.findall( r'\b' + i[0] + r'\s*\(', l )
73                 if m and m[0]:
74                     m = re.findall( r'[\s\(\*]([\w\.\->\[\]]+)\s*=[^=]', l )
75                     if not m or not m[0]:
76                         print "%s(%d): function %s: no variable found in create function" % \
77                             (srcname, lineno, fname)
78                         break
79                     #assert (m and m[0]) # if "create" is called,
80                     #                    # there should be a target pointer
81                     allocdict[m[0]] = (i[1],1)
82                     break
83         # the same notice as for cvAlloc & cvCreate
84         elif l.find( 'Free') >= 0 or l.find('Release') >= 0:
85             for i in allocfuncs:
86                 m = re.findall( r'\b' + i[1] + r'\s*\(', l )
87                 if m and m[0]:
88                     m = re.findall( r'([\w\.\->\[\]]+)[\s\)]+;', l )
89                     #assert (m and m[0]) # if "release" is called,
90                     #                    # there should be a released pointer (last argument)
91                     if not m or not m[0]:
92                         print "%s(%d): function %s: no variable found in release function" % \
93                             (srcname, lineno, fname)
94                         break
95                     p = allocdict.get(m[0],("",0))
96                     if not p[0]:
97                         print "%s(%d): function %s: unmatching release of %s" % \
98                             (srcname, lineno, fname, m[0])
99                         
100                     #assert (p[0] == i[1]) # "release" function should match
101                     #                      # the "create" function used
102                     allocdict[m[0]] = (p[0],p[1]-1)
103                     break
104
105     f.close()
106
107 print "Result: %d potential leaks found, %d out of them are possible false alarms" % (leaks, falsealarms)