|
1 # ################################################################# |
|
2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 # All rights reserved. |
|
4 # |
|
5 # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
|
6 # |
|
7 # * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
|
8 # * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. |
|
9 # * Neither the name of Nokia Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. |
|
10 # |
|
11 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
|
12 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS |
|
13 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
14 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
15 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# |
|
16 # |
|
17 # forgottoputptroncleanupstack.py |
|
18 # |
|
19 # Checks : Neglected to put variable on cleanup stack. |
|
20 # |
|
21 # Reason : If a variable is not put on the cleanup stack and a |
|
22 # leaving function or ELeave is called, a memory leak occurs. |
|
23 # CodeScanner occasionally gives false positives for this issue. |
|
24 # Individual cases should be investigated. |
|
25 # |
|
26 # ################################################################# |
|
27 |
|
28 script = CScript("forgottoputptroncleanupstack") |
|
29 script.iReString = r""" |
|
30 \s+ # optional whitespace |
|
31 [b-hj-z]+ # must not be a member or parameter |
|
32 [A-Za-z0-9]+ # variable name |
|
33 \s* # optional whitespace |
|
34 = # assignment operator |
|
35 """ |
|
36 script.iFileExts = ["cpp"] |
|
37 script.iCategory = KCategoryCodeReviewGuides |
|
38 script.iIgnore = KIgnoreCommentsAndQuotes |
|
39 script.iSeverity = KSeverityLow |
|
40 |
|
41 forgottoputptroncleanupstackCleanup = re.compile("""Cleanup""", re.VERBOSE) |
|
42 |
|
43 forgottoputptroncleanupstackDeleteOp = re.compile(""" |
|
44 \s+ |
|
45 delete |
|
46 \s+ |
|
47 """, re.VERBOSE) |
|
48 |
|
49 forgottoputptroncleanupstackReturnCmd = re.compile(""" |
|
50 (\s*|\() |
|
51 return |
|
52 (\s*|\() |
|
53 """, re.VERBOSE) |
|
54 |
|
55 forgottoputptroncleanupstackSetFn = re.compile(""" |
|
56 Set |
|
57 [A-Za-z0-9]+ |
|
58 [A-KM-Za-z0-9] |
|
59 \s* |
|
60 \( |
|
61 """, re.VERBOSE) |
|
62 |
|
63 forgottoputptroncleanupstackBreak = re.compile(""" |
|
64 \s+ |
|
65 break |
|
66 \s* |
|
67 ; |
|
68 """, re.VERBOSE) |
|
69 |
|
70 forgottoputptroncleanupstackIf = re.compile(""" |
|
71 \s+ |
|
72 if |
|
73 \s* |
|
74 \( |
|
75 """, re.VERBOSE) |
|
76 |
|
77 forgottoputptroncleanupstackElse = re.compile(""" |
|
78 \}* |
|
79 \s* |
|
80 else |
|
81 \s* |
|
82 \{* |
|
83 """, re.VERBOSE) |
|
84 |
|
85 forgottoputptroncleanupstackAssignToMember = re.compile(""" |
|
86 i |
|
87 [A-Za-z0-9\[\]]+ |
|
88 \s* |
|
89 = |
|
90 \s* |
|
91 .* |
|
92 \s* |
|
93 ; |
|
94 """, re.VERBOSE) |
|
95 |
|
96 forgottoputptroncleanupstackTrapMacro = re.compile(""" |
|
97 TRAP |
|
98 [D]* |
|
99 \s* |
|
100 \( |
|
101 """, re.VERBOSE) |
|
102 |
|
103 forgottoputptroncleanupstackLeavingFunction = re.compile(""" |
|
104 [A-Za-z0-9]+ |
|
105 L |
|
106 \s* |
|
107 \( |
|
108 """, re.VERBOSE) |
|
109 |
|
110 forgottoputptroncleanupstackLeave = re.compile(""" |
|
111 User::Leave |
|
112 """, re.VERBOSE) |
|
113 |
|
114 forgottoputptroncleanupstackLeaveAndDelete = re.compile(""" |
|
115 L |
|
116 [D]+ |
|
117 \s* |
|
118 \( |
|
119 """, re.VERBOSE) |
|
120 |
|
121 forgottoputptroncleanupstackNewOperator = re.compile(""" |
|
122 new |
|
123 \s* |
|
124 \( |
|
125 \s* |
|
126 ELeave |
|
127 """, re.VERBOSE) |
|
128 |
|
129 forgottoputptroncleanupstackNewFunction = re.compile(""" |
|
130 ::NewL |
|
131 \s* |
|
132 \( |
|
133 """, re.VERBOSE) |
|
134 |
|
135 forgottoputptroncleanupstackCreateFunction = re.compile(""" |
|
136 Create |
|
137 [A-Za-z0-9]+ |
|
138 L |
|
139 \s* |
|
140 \( |
|
141 """, re.VERBOSE) |
|
142 |
|
143 forgottoputptroncleanupstackAllocFunction = re.compile(""" |
|
144 Alloc |
|
145 L* |
|
146 \s* |
|
147 \( |
|
148 """, re.VERBOSE) |
|
149 |
|
150 def findForgetCompare(lines, currentline, rematch, filename): |
|
151 line = lines[currentline] |
|
152 m = rematch.search(line) |
|
153 |
|
154 if m: |
|
155 foundNew = 0 |
|
156 equalPos = line.find("=") |
|
157 assignedSection = line[equalPos:] |
|
158 |
|
159 if forgottoputptroncleanupstackNewFunction.search(assignedSection): |
|
160 foundNew = 1 |
|
161 if forgottoputptroncleanupstackNewOperator.search(assignedSection): |
|
162 foundNew = 1 |
|
163 if forgottoputptroncleanupstackAllocFunction.search(assignedSection): |
|
164 foundNew = 1 |
|
165 if forgottoputptroncleanupstackCreateFunction.search(assignedSection): |
|
166 foundNew = 1 |
|
167 |
|
168 # if this line contains a 'new', a 'NewL(', or an 'AllocL(' |
|
169 if (foundNew == 1): |
|
170 i = currentline |
|
171 |
|
172 # move to next line ending if this line doesn't contain one |
|
173 while (lines[i].find(';') == -1): |
|
174 i = i + 1 |
|
175 |
|
176 # go to next line |
|
177 i = i + 1 |
|
178 bracketdepth = GetBracketDepth(lines, i) |
|
179 |
|
180 # get the variable name, between the '*' and the '=' |
|
181 startindex = line.find("*") |
|
182 if (startindex == -1): |
|
183 startindex = 0 |
|
184 endindex = line.find("=") |
|
185 variable = line[startindex+1:endindex] |
|
186 if (len(variable) < 1): |
|
187 return 0 |
|
188 variable = TrimVariableName(variable) |
|
189 |
|
190 inAnIfOrSelectStatement = 1 # possibly |
|
191 |
|
192 while (i < len(lines)): |
|
193 line2 = lines[i] |
|
194 |
|
195 if (line2.find('{') >= 0): |
|
196 bracketdepth = bracketdepth + 1 |
|
197 if (line2.find('}') >= 0): |
|
198 bracketdepth = bracketdepth - 1 |
|
199 inAnIfOrSelectStatement = 0 |
|
200 if (bracketdepth == 0): |
|
201 return 0 |
|
202 |
|
203 varIndex = line2.find(variable) |
|
204 # if a later line contains the variable... |
|
205 while (varIndex <> -1): |
|
206 if (isNonAlpha(line2[varIndex-1])): |
|
207 if (isNonAlpha(line2[varIndex+len(variable)])): |
|
208 # ...and delete, exit |
|
209 if forgottoputptroncleanupstackDeleteOp.search(line2): |
|
210 return 0 |
|
211 |
|
212 # ...and an xxxLD() function, exit |
|
213 if forgottoputptroncleanupstackLeaveAndDelete.search(line2): |
|
214 return 0 |
|
215 |
|
216 # ...and the variable is assigned to a member variable, exit |
|
217 if forgottoputptroncleanupstackAssignToMember.search(line2): |
|
218 return 0 |
|
219 |
|
220 # ...and it is a Set...() call, exit (e.g. SetArray, SetAppUi) |
|
221 if forgottoputptroncleanupstackSetFn.search(line2): |
|
222 return 0 |
|
223 |
|
224 # ...and a return command, exit |
|
225 if forgottoputptroncleanupstackReturnCmd.search(line2): |
|
226 return 0 |
|
227 |
|
228 # search this line again incase there are similarly named variables |
|
229 line2 = line2[varIndex+1:] |
|
230 varIndex = line2.find(variable) |
|
231 |
|
232 line2 = lines[i] |
|
233 # if a leaving function is called... |
|
234 if forgottoputptroncleanupstackLeavingFunction.search(line2): |
|
235 # ...if the leaving function is trapped, exit |
|
236 if forgottoputptroncleanupstackTrapMacro.search(line2): |
|
237 return 0 |
|
238 # ...if a Cleanup function is called, exit |
|
239 if forgottoputptroncleanupstackCleanup.search(line2): |
|
240 return 0 |
|
241 # ...otherwise this is a problem! |
|
242 return 1 |
|
243 |
|
244 # if a User::Leave is called, this is a problem |
|
245 if forgottoputptroncleanupstackLeave.search(line2): |
|
246 return 1 |
|
247 |
|
248 # if the variable is initialised in a branch of an 'if' or 'switch' statement, ignore other branches |
|
249 if (inAnIfOrSelectStatement == 1): |
|
250 if forgottoputptroncleanupstackBreak.search(line2): |
|
251 atLine = i |
|
252 inAnIfOrSelectStatement = 0 |
|
253 findSwitch = i |
|
254 line3 = lines[findSwitch] |
|
255 while (line3.find("switch") == -1): |
|
256 findSwitch = findSwitch - 1 |
|
257 if (findSwitch <= 0): |
|
258 return 0 |
|
259 line3 = lines[findSwitch] |
|
260 switchBracketDepth = GetBracketDepth(lines, findSwitch) |
|
261 i = atLine |
|
262 while (bracketdepth > switchBracketDepth): |
|
263 if (i >= len(lines)): |
|
264 return 0 |
|
265 line2 = lines[i] |
|
266 if (line2.find('{') >= 0): |
|
267 bracketdepth = bracketdepth + 1 |
|
268 if (line2.find('}') >= 0): |
|
269 bracketdepth = bracketdepth - 1 |
|
270 i = i + 1 |
|
271 |
|
272 if forgottoputptroncleanupstackElse.search(line2): |
|
273 inAnIfOrSelectStatement = 0 |
|
274 elseBracketDepth = bracketdepth |
|
275 if (line2.find('{') >= 0): |
|
276 elseBracketDepth = elseBracketDepth - 1 |
|
277 if (elseBracketDepth == GetBracketDepth(lines, currentline)): |
|
278 while (line2.find(';') == -1): |
|
279 i = i + 1 |
|
280 if (i >= len(lines)): |
|
281 return 0 |
|
282 line2 = lines[i] |
|
283 else: |
|
284 while (bracketdepth > elseBracketDepth): |
|
285 i = i + 1 |
|
286 if (i >= len(lines)): |
|
287 return 0 |
|
288 line2 = lines[i] |
|
289 if (line2.find('{') >= 0): |
|
290 bracketdepth = bracketdepth + 1 |
|
291 if (line2.find('}') >= 0): |
|
292 bracketdepth = bracketdepth - 1 |
|
293 |
|
294 if forgottoputptroncleanupstackIf.search(line2): |
|
295 inAnIfOrSelectStatement = 0 |
|
296 i = i + 1 |
|
297 return 0 |
|
298 |
|
299 return 0 |
|
300 |
|
301 script.iCompare = findForgetCompare |
|
302 scanner.AddScript(script) |