Branch data Line data Source code
1 : : /*
2 : : * Cppcheck - A tool for static C/C++ code analysis
3 : : * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
4 : : *
5 : : * This program is free software: you can redistribute it and/or modify
6 : : * it under the terms of the GNU General Public License as published by
7 : : * the Free Software Foundation, either version 3 of the License, or
8 : : * (at your option) any later version.
9 : : *
10 : : * This program is distributed in the hope that it will be useful,
11 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : : * GNU General Public License for more details.
14 : : *
15 : : * You should have received a copy of the GNU General Public License
16 : : * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 : : */
18 : :
19 : :
20 : : //---------------------------------------------------------------------------
21 : : #include "checknullpointer.h"
22 : : #include "executionpath.h"
23 : : #include "mathlib.h"
24 : : #include "symboldatabase.h"
25 : : #include <cctype>
26 : : //---------------------------------------------------------------------------
27 : :
28 : : // Register this check class (by creating a static instance of it)
29 : : namespace {
30 : 45 : CheckNullPointer instance;
31 : : }
32 : :
33 : : //---------------------------------------------------------------------------
34 : :
35 : : /**
36 : : * @brief parse a function call and extract information about variable usage
37 : : * @param tok first token
38 : : * @param var variables that the function read / write.
39 : : * @param value 0 => invalid with null pointers as parameter.
40 : : * 1-.. => invalid with uninitialized data.
41 : : */
42 : 25321 : void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token *> &var, unsigned char value)
43 : : {
44 : : // standard functions that dereference first parameter..
45 [ + + ][ + - ]: 25321 : static std::set<std::string> functionNames1_all;
[ + - ][ # # ]
46 [ + + ][ + - ]: 25321 : static std::set<std::string> functionNames1_nullptr;
[ + - ][ # # ]
47 [ + + ][ + - ]: 25321 : static std::set<std::string> functionNames1_uninit;
[ + - ][ # # ]
48 [ + + ]: 25321 : if (functionNames1_all.empty()) {
49 : : // cstdlib
50 [ + - ][ + - ]: 45 : functionNames1_all.insert("atoi");
[ + - ]
51 [ + - ][ + - ]: 45 : functionNames1_all.insert("atof");
[ + - ]
52 [ + - ][ + - ]: 45 : functionNames1_all.insert("atol");
[ + - ]
53 [ + - ][ + - ]: 45 : functionNames1_all.insert("qsort");
[ + - ]
54 [ + - ][ + - ]: 45 : functionNames1_all.insert("strtof");
[ + - ]
55 [ + - ][ + - ]: 45 : functionNames1_all.insert("strtod");
[ + - ]
56 [ + - ][ + - ]: 45 : functionNames1_all.insert("strtol");
[ + - ]
57 [ + - ][ + - ]: 45 : functionNames1_all.insert("strtoul");
[ + - ]
58 [ + - ][ + - ]: 45 : functionNames1_all.insert("strtold");
[ + - ]
59 [ + - ][ + - ]: 45 : functionNames1_all.insert("strtoll");
[ + - ]
60 [ + - ][ + - ]: 45 : functionNames1_all.insert("strtoull");
[ + - ]
61 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcstof");
[ + - ]
62 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcstod");
[ + - ]
63 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcstol");
[ + - ]
64 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcstoul");
[ + - ]
65 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcstold");
[ + - ]
66 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcstoll");
[ + - ]
67 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcstoull");
[ + - ]
68 : : // cstring
69 [ + - ][ + - ]: 45 : functionNames1_all.insert("memchr");
[ + - ]
70 [ + - ][ + - ]: 45 : functionNames1_all.insert("memcmp");
[ + - ]
71 [ + - ][ + - ]: 45 : functionNames1_all.insert("strcat");
[ + - ]
72 [ + - ][ + - ]: 45 : functionNames1_all.insert("strncat");
[ + - ]
73 [ + - ][ + - ]: 45 : functionNames1_all.insert("strcoll");
[ + - ]
74 [ + - ][ + - ]: 45 : functionNames1_all.insert("strchr");
[ + - ]
75 [ + - ][ + - ]: 45 : functionNames1_all.insert("strrchr");
[ + - ]
76 [ + - ][ + - ]: 45 : functionNames1_all.insert("strcmp");
[ + - ]
77 [ + - ][ + - ]: 45 : functionNames1_all.insert("strncmp");
[ + - ]
78 [ + - ][ + - ]: 45 : functionNames1_all.insert("strcspn");
[ + - ]
79 [ + - ][ + - ]: 45 : functionNames1_all.insert("strdup");
[ + - ]
80 [ + - ][ + - ]: 45 : functionNames1_all.insert("strndup");
[ + - ]
81 [ + - ][ + - ]: 45 : functionNames1_all.insert("strpbrk");
[ + - ]
82 [ + - ][ + - ]: 45 : functionNames1_all.insert("strlen");
[ + - ]
83 [ + - ][ + - ]: 45 : functionNames1_all.insert("strspn");
[ + - ]
84 [ + - ][ + - ]: 45 : functionNames1_all.insert("strstr");
[ + - ]
85 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcscat");
[ + - ]
86 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcsncat");
[ + - ]
87 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcscoll");
[ + - ]
88 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcschr");
[ + - ]
89 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcsrchr");
[ + - ]
90 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcscmp");
[ + - ]
91 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcsncmp");
[ + - ]
92 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcscspn");
[ + - ]
93 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcsdup");
[ + - ]
94 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcsndup");
[ + - ]
95 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcspbrk");
[ + - ]
96 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcslen");
[ + - ]
97 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcsspn");
[ + - ]
98 [ + - ][ + - ]: 45 : functionNames1_all.insert("wcsstr");
[ + - ]
99 : : // cstdio
100 [ + - ][ + - ]: 45 : functionNames1_all.insert("fclose");
[ + - ]
101 [ + - ][ + - ]: 45 : functionNames1_all.insert("feof");
[ + - ]
102 [ + - ][ + - ]: 45 : functionNames1_all.insert("fwrite");
[ + - ]
103 [ + - ][ + - ]: 45 : functionNames1_all.insert("fseek");
[ + - ]
104 [ + - ][ + - ]: 45 : functionNames1_all.insert("ftell");
[ + - ]
105 [ + - ][ + - ]: 45 : functionNames1_all.insert("fputs");
[ + - ]
106 [ + - ][ + - ]: 45 : functionNames1_all.insert("fputws");
[ + - ]
107 [ + - ][ + - ]: 45 : functionNames1_all.insert("ferror");
[ + - ]
108 [ + - ][ + - ]: 45 : functionNames1_all.insert("fgetc");
[ + - ]
109 [ + - ][ + - ]: 45 : functionNames1_all.insert("fgetwc");
[ + - ]
110 [ + - ][ + - ]: 45 : functionNames1_all.insert("fgetpos");
[ + - ]
111 [ + - ][ + - ]: 45 : functionNames1_all.insert("fsetpos");
[ + - ]
112 [ + - ][ + - ]: 45 : functionNames1_all.insert("freopen");
[ + - ]
113 [ + - ][ + - ]: 45 : functionNames1_all.insert("fscanf");
[ + - ]
114 [ + - ][ + - ]: 45 : functionNames1_all.insert("fprintf");
[ + - ]
115 [ + - ][ + - ]: 45 : functionNames1_all.insert("fwscanf");
[ + - ]
116 [ + - ][ + - ]: 45 : functionNames1_all.insert("fwprintf");
[ + - ]
117 [ + - ][ + - ]: 45 : functionNames1_all.insert("fopen");
[ + - ]
118 [ + - ][ + - ]: 45 : functionNames1_all.insert("rewind");
[ + - ]
119 [ + - ][ + - ]: 45 : functionNames1_all.insert("printf");
[ + - ]
120 [ + - ][ + - ]: 45 : functionNames1_all.insert("wprintf");
[ + - ]
121 [ + - ][ + - ]: 45 : functionNames1_all.insert("scanf");
[ + - ]
122 [ + - ][ + - ]: 45 : functionNames1_all.insert("wscanf");
[ + - ]
123 [ + - ][ + - ]: 45 : functionNames1_all.insert("fscanf");
[ + - ]
124 [ + - ][ + - ]: 45 : functionNames1_all.insert("sscanf");
[ + - ]
125 [ + - ][ + - ]: 45 : functionNames1_all.insert("fwscanf");
[ + - ]
126 [ + - ][ + - ]: 45 : functionNames1_all.insert("swscanf");
[ + - ]
127 [ + - ][ + - ]: 45 : functionNames1_all.insert("setbuf");
[ + - ]
128 [ + - ][ + - ]: 45 : functionNames1_all.insert("setvbuf");
[ + - ]
129 [ + - ][ + - ]: 45 : functionNames1_all.insert("rename");
[ + - ]
130 [ + - ][ + - ]: 45 : functionNames1_all.insert("remove");
[ + - ]
131 [ + - ][ + - ]: 45 : functionNames1_all.insert("puts");
[ + - ]
132 [ + - ][ + - ]: 45 : functionNames1_all.insert("getc");
[ + - ]
133 [ + - ][ + - ]: 45 : functionNames1_all.insert("clearerr");
[ + - ]
134 : : // ctime
135 [ + - ][ + - ]: 45 : functionNames1_all.insert("asctime");
[ + - ]
136 [ + - ][ + - ]: 45 : functionNames1_all.insert("ctime");
[ + - ]
137 [ + - ][ + - ]: 45 : functionNames1_all.insert("mktime");
[ + - ]
138 : :
139 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("itoa");
[ + - ]
140 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("memcpy");
[ + - ]
141 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("memmove");
[ + - ]
142 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("memset");
[ + - ]
143 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("strcpy");
[ + - ]
144 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("sprintf");
[ + - ]
145 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("vsprintf");
[ + - ]
146 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("vprintf");
[ + - ]
147 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("fprintf");
[ + - ]
148 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("vfprintf");
[ + - ]
149 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("wcscpy");
[ + - ]
150 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("swprintf");
[ + - ]
151 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("vswprintf");
[ + - ]
152 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("vwprintf");
[ + - ]
153 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("fwprintf");
[ + - ]
154 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("vfwprintf");
[ + - ]
155 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("fread");
[ + - ]
156 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("gets");
[ + - ]
157 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("gmtime");
[ + - ]
158 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("localtime");
[ + - ]
159 [ + - ][ + - ]: 45 : functionNames1_nullptr.insert("strftime");
[ + - ]
160 : :
161 [ + - ][ + - ]: 45 : functionNames1_uninit.insert("perror");
[ + - ]
162 [ + - ][ + - ]: 45 : functionNames1_uninit.insert("fflush");
[ + - ]
163 : : }
164 : :
165 : : // standard functions that dereference second parameter..
166 [ + + ][ + - ]: 25321 : static std::set<std::string> functionNames2_all;
[ + - ][ # # ]
167 [ + + ][ + - ]: 25321 : static std::set<std::string> functionNames2_nullptr;
[ + - ][ # # ]
168 [ + + ]: 25321 : if (functionNames2_all.empty()) {
169 [ + - ][ + - ]: 45 : functionNames2_all.insert("mbstowcs");
[ + - ]
170 [ + - ][ + - ]: 45 : functionNames2_all.insert("wcstombs");
[ + - ]
171 [ + - ][ + - ]: 45 : functionNames2_all.insert("memcmp");
[ + - ]
172 [ + - ][ + - ]: 45 : functionNames2_all.insert("memcpy");
[ + - ]
173 [ + - ][ + - ]: 45 : functionNames2_all.insert("memmove");
[ + - ]
174 [ + - ][ + - ]: 45 : functionNames2_all.insert("strcat");
[ + - ]
175 [ + - ][ + - ]: 45 : functionNames2_all.insert("strncat");
[ + - ]
176 [ + - ][ + - ]: 45 : functionNames2_all.insert("strcmp");
[ + - ]
177 [ + - ][ + - ]: 45 : functionNames2_all.insert("strncmp");
[ + - ]
178 [ + - ][ + - ]: 45 : functionNames2_all.insert("strcoll");
[ + - ]
179 [ + - ][ + - ]: 45 : functionNames2_all.insert("strcpy");
[ + - ]
180 [ + - ][ + - ]: 45 : functionNames2_all.insert("strcspn");
[ + - ]
181 [ + - ][ + - ]: 45 : functionNames2_all.insert("strncpy");
[ + - ]
182 [ + - ][ + - ]: 45 : functionNames2_all.insert("strpbrk");
[ + - ]
183 [ + - ][ + - ]: 45 : functionNames2_all.insert("strspn");
[ + - ]
184 [ + - ][ + - ]: 45 : functionNames2_all.insert("strstr");
[ + - ]
185 [ + - ][ + - ]: 45 : functionNames2_all.insert("strxfrm");
[ + - ]
186 [ + - ][ + - ]: 45 : functionNames2_all.insert("wcscat");
[ + - ]
187 [ + - ][ + - ]: 45 : functionNames2_all.insert("wcsncat");
[ + - ]
188 [ + - ][ + - ]: 45 : functionNames2_all.insert("wcscmp");
[ + - ]
189 [ + - ][ + - ]: 45 : functionNames2_all.insert("wcsncmp");
[ + - ]
190 [ + - ][ + - ]: 45 : functionNames2_all.insert("wcscoll");
[ + - ]
191 [ + - ][ + - ]: 45 : functionNames2_all.insert("wcscpy");
[ + - ]
192 [ + - ][ + - ]: 45 : functionNames2_all.insert("wcscspn");
[ + - ]
193 [ + - ][ + - ]: 45 : functionNames2_all.insert("wcsncpy");
[ + - ]
194 [ + - ][ + - ]: 45 : functionNames2_all.insert("wcspbrk");
[ + - ]
195 [ + - ][ + - ]: 45 : functionNames2_all.insert("wcsspn");
[ + - ]
196 [ + - ][ + - ]: 45 : functionNames2_all.insert("wcsstr");
[ + - ]
197 [ + - ][ + - ]: 45 : functionNames2_all.insert("wcsxfrm");
[ + - ]
198 [ + - ][ + - ]: 45 : functionNames2_all.insert("sprintf");
[ + - ]
199 [ + - ][ + - ]: 45 : functionNames2_all.insert("fprintf");
[ + - ]
200 [ + - ][ + - ]: 45 : functionNames2_all.insert("fscanf");
[ + - ]
201 [ + - ][ + - ]: 45 : functionNames2_all.insert("sscanf");
[ + - ]
202 [ + - ][ + - ]: 45 : functionNames2_all.insert("swprintf");
[ + - ]
203 [ + - ][ + - ]: 45 : functionNames2_all.insert("fwprintf");
[ + - ]
204 [ + - ][ + - ]: 45 : functionNames2_all.insert("fwscanf");
[ + - ]
205 [ + - ][ + - ]: 45 : functionNames2_all.insert("swscanf");
[ + - ]
206 [ + - ][ + - ]: 45 : functionNames2_all.insert("fputs");
[ + - ]
207 [ + - ][ + - ]: 45 : functionNames2_all.insert("fputc");
[ + - ]
208 [ + - ][ + - ]: 45 : functionNames2_all.insert("ungetc");
[ + - ]
209 [ + - ][ + - ]: 45 : functionNames2_all.insert("fputws");
[ + - ]
210 [ + - ][ + - ]: 45 : functionNames2_all.insert("fputwc");
[ + - ]
211 [ + - ][ + - ]: 45 : functionNames2_all.insert("ungetwc");
[ + - ]
212 [ + - ][ + - ]: 45 : functionNames2_all.insert("rename");
[ + - ]
213 [ + - ][ + - ]: 45 : functionNames2_all.insert("putc");
[ + - ]
214 [ + - ][ + - ]: 45 : functionNames2_all.insert("putwc");
[ + - ]
215 [ + - ][ + - ]: 45 : functionNames2_all.insert("freopen");
[ + - ]
216 : :
217 [ + - ][ + - ]: 45 : functionNames2_nullptr.insert("frexp");
[ + - ]
218 [ + - ][ + - ]: 45 : functionNames2_nullptr.insert("modf");
[ + - ]
219 [ + - ][ + - ]: 45 : functionNames2_nullptr.insert("fgetpos");
[ + - ]
220 : : }
221 : :
222 [ + + ][ - + ]: 25321 : if (Token::Match(&tok, "%var% ( )") || !tok.tokAt(2))
[ + + ]
223 : 3945 : return;
224 : :
225 : 21376 : const Token* firstParam = tok.tokAt(2);
226 : 21376 : const Token* secondParam = firstParam->nextArgument();
227 : :
228 : : // 1st parameter..
229 [ + + ][ + + ]: 37410 : if ((Token::Match(firstParam, "%var% ,|)") && firstParam->varId() > 0) ||
[ + + + + ]
[ + + ]
230 : 16034 : (value == 0 && Token::Match(firstParam, "0 ,|)"))) {
231 [ + + ]: 5984 : if (functionNames1_all.find(tok.str()) != functionNames1_all.end())
232 : 886 : var.push_back(firstParam);
233 [ + + ][ + + ]: 5098 : else if (value == 0 && functionNames1_nullptr.find(tok.str()) != functionNames1_nullptr.end())
[ + + ]
234 : 596 : var.push_back(firstParam);
235 [ + + ][ + + ]: 4502 : else if (value != 0 && functionNames1_uninit.find(tok.str()) != functionNames1_uninit.end())
[ + + ]
236 : 2 : var.push_back(firstParam);
237 [ + + ][ + + ]: 4500 : else if (value == 0 && Token::Match(&tok, "snprintf|vsnprintf|fnprintf|vfnprintf") && secondParam && secondParam->str() != "0") // Only if length (second parameter) is not zero
[ + - ][ + + ]
[ + + ]
238 : 90 : var.push_back(firstParam);
239 : : }
240 : :
241 : : // 2nd parameter..
242 [ + + ][ + + ]: 21376 : if (secondParam && ((value == 0 && secondParam->str() == "0") || (secondParam->varId() > 0))) {
[ + + ][ + + ]
[ + + ]
243 [ + + ]: 1869 : if (functionNames2_all.find(tok.str()) != functionNames2_all.end())
244 : 423 : var.push_back(secondParam);
245 [ + + ][ + + ]: 1446 : else if (value == 0 && functionNames2_nullptr.find(tok.str()) != functionNames2_nullptr.end())
[ + + ]
246 : 180 : var.push_back(secondParam);
247 : : }
248 : :
249 [ + + ]: 21376 : if (Token::Match(&tok, "printf|sprintf|snprintf|fprintf|fnprintf|scanf|sscanf|fscanf|wprintf|swprintf|fwprintf|wscanf|swscanf|fwscanf")) {
250 : 2792 : const Token* argListTok = 0; // Points to first va_list argument
251 : 2792 : std::string formatString;
252 [ + - ]: 2792 : bool scan = Token::Match(&tok, "scanf|sscanf|fscanf|wscanf|swscanf|fwscanf");
253 : :
254 [ + - ][ + + ]: 2792 : if (Token::Match(&tok, "printf|scanf|wprintf|wscanf ( %str%")) {
255 [ + - ][ + - ]: 1712 : formatString = firstParam->strValue();
[ + - ]
256 : 1712 : argListTok = secondParam;
257 [ + - ][ + + ]: 1080 : } else if (Token::Match(&tok, "sprintf|fprintf|sscanf|fscanf|fwprintf|fwscanf|swscanf")) {
258 : 900 : const Token* formatStringTok = secondParam; // Find second parameter (format string)
259 [ + - ][ + + ]: 900 : if (formatStringTok && formatStringTok->type() == Token::eString) {
[ + + ]
260 [ + - ]: 810 : argListTok = formatStringTok->nextArgument(); // Find third parameter (first argument of va_args)
261 [ + - ][ + - ]: 810 : formatString = formatStringTok->strValue();
[ + - ]
262 : : }
263 [ + - ][ + - ]: 180 : } else if (Token::Match(&tok, "snprintf|fnprintf|swprintf") && secondParam) {
[ + - ][ + - ]
264 [ + - ]: 180 : const Token* formatStringTok = secondParam->nextArgument(); // Find third parameter (format string)
265 [ + - ][ + - ]: 180 : if (formatStringTok && formatStringTok->type() == Token::eString) {
[ + - ]
266 [ + - ]: 180 : argListTok = formatStringTok->nextArgument(); // Find fourth parameter (first argument of va_args)
267 [ + - ][ + - ]: 180 : formatString = formatStringTok->strValue();
[ + - ]
268 : : }
269 : : }
270 : :
271 [ + + ]: 2792 : if (argListTok) {
272 : 2702 : bool percent = false;
273 [ + - ][ + - ]: 13236 : for (std::string::iterator i = formatString.begin(); i != formatString.end(); ++i) {
[ + - ][ + - ]
274 [ + + ]: 10534 : if (*i == '%') {
275 : 3782 : percent = !percent;
276 [ + + ]: 6752 : } else if (percent) {
277 : 3602 : percent = false;
278 : :
279 : 3602 : bool _continue = false;
280 [ + + ]: 4052 : while (!std::isalpha(*i)) {
281 [ + + ]: 540 : if (*i == '*') {
282 [ + + ]: 360 : if (scan)
283 : 90 : _continue = true;
284 : : else
285 [ + - ]: 270 : argListTok = argListTok->nextArgument();
286 : : }
287 : 540 : ++i;
288 [ + + ][ + - ]: 540 : if (!argListTok || i == formatString.end())
[ + - ][ - + ]
[ + + ]
289 : : return;
290 : : }
291 [ + + ]: 3512 : if (_continue)
292 : 90 : continue;
293 : :
294 [ + - ][ + + ]: 3422 : if ((*i == 'n' || *i == 's' || scan) && (!scan || value == 0)) {
[ + + ][ + + ]
[ + - ][ + + ]
295 [ + + ][ + - ]: 2342 : if ((value == 0 && argListTok->str() == "0") || (argListTok->varId() > 0)) {
[ + + ][ + + ]
[ + + ]
296 [ + - ]: 1892 : var.push_back(argListTok);
297 : : }
298 : : }
299 : :
300 [ + + ]: 3422 : if (*i != 'm') // %m is a non-standard glibc extension that requires no parameter
301 [ + - ]: 3332 : argListTok = argListTok->nextArgument(); // Find next argument
302 [ + + ]: 3422 : if (!argListTok)
303 : 2612 : break;
304 : : }
305 : : }
306 : 25321 : }
307 : : }
308 : : }
309 : :
310 : :
311 : : /**
312 : : * Is there a pointer dereference? Everything that should result in
313 : : * a nullpointer dereference error message will result in a true
314 : : * return value. If it's unknown if the pointer is dereferenced false
315 : : * is returned.
316 : : * @param tok token for the pointer
317 : : * @param unknown it is not known if there is a pointer dereference (could be reported as a debug message)
318 : : * @return true => there is a dereference
319 : : */
320 : 45337 : bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown)
321 : : {
322 : 45337 : const bool inconclusive = unknown;
323 : :
324 : 45337 : unknown = false;
325 : :
326 : : // Dereferencing pointer..
327 [ + + ][ + + ]: 45337 : if (tok->strAt(-1) == "*" && (Token::Match(tok->tokAt(-2), "return|throw|;|{|}|:|[|(|,") || tok->tokAt(-2)->isOp()) && !Token::Match(tok->tokAt(-3), "sizeof|decltype"))
[ + + ][ + + ]
[ + + ]
328 : 4095 : return true;
329 : :
330 : : // read/write member variable
331 [ + + ][ + - ]: 41242 : if (!Token::simpleMatch(tok->tokAt(-2), "& (") && !Token::Match(tok->tokAt(-2), "sizeof|decltype (") && tok->strAt(-1) != "&" && Token::Match(tok->next(), ". %var%")) {
[ + + ][ + + ]
[ + + ]
332 [ + + ]: 5132 : if (tok->strAt(3) != "(")
333 : 3197 : return true;
334 : 1935 : unknown = true;
335 : 1935 : return false;
336 : : }
337 : :
338 [ + + ][ - + ]: 36110 : if (Token::Match(tok, "%var% [") && (tok->previous()->str() != "&" || Token::Match(tok->next()->link()->next(), "[.(]")))
[ # # ][ + + ]
339 : 721 : return true;
340 : :
341 [ + + ]: 35389 : if (Token::Match(tok, "%var% ("))
342 : 180 : return true;
343 : :
344 [ + + + - : 37371 : if (Token::Match(tok, "%var% = %var% .") &&
+ + ][ + + ]
345 : 1081 : tok->varId() > 0 &&
346 : 1081 : tok->varId() == tok->tokAt(2)->varId())
347 : 675 : return true;
348 : :
349 : : // std::string dereferences nullpointers
350 [ + + ]: 34534 : if (Token::Match(tok->tokAt(-4), "std :: string|wstring ( %var% )"))
351 : 45 : return true;
352 [ + + ]: 34489 : if (Token::Match(tok->tokAt(-2), "%var% ( %var% )")) {
353 : 3607 : const Variable* var = tok->tokAt(-2)->variable();
354 [ + + ][ + - ]: 3607 : if (var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "std :: string|wstring !!::"))
[ + - ][ + + ]
[ + + ]
355 : 45 : return true;
356 : : }
357 : :
358 : : // streams dereference nullpointers
359 [ + + ]: 34444 : if (Token::Match(tok->previous(), "<<|>> %var%")) {
360 : 720 : const Variable* var = tok->variable();
361 [ + - ][ + + ]: 720 : if (var && var->isPointer() && Token::Match(var->typeStartToken(), "char|wchar_t")) { // Only outputting or reading to char* can cause problems
[ + + ][ + + ]
362 : 495 : const Token* tok2 = tok->previous(); // Find start of statement
363 [ + - ]: 2070 : for (; tok2; tok2 = tok2->previous()) {
364 [ + + ]: 2070 : if (Token::Match(tok2->previous(), ";|{|}|:"))
365 : 495 : break;
366 : : }
367 [ + + ]: 495 : if (Token::Match(tok2, "std :: cout|cin|cerr"))
368 : 360 : return true;
369 [ + - ][ + - ]: 135 : if (tok2 && tok2->varId() != 0) {
[ + - ]
370 : 135 : const Variable* var2 = tok2->variable();
371 [ + - ][ + - ]: 135 : if (var2 && Token::Match(var2->typeStartToken(), "std :: istream|ifstream|istringstream|wistringstream|ostream|ofstream|ostringstream|wostringstream|stringstream|wstringstream|fstream|iostream"))
[ + - ]
372 : 135 : return true;
373 : : }
374 : : }
375 : : }
376 : :
377 : 33949 : const Variable *ovar = NULL;
378 [ + + ]: 33949 : if (Token::Match(tok, "%var% ==|!= %var%"))
379 : 225 : ovar = tok->tokAt(2)->variable();
380 [ + + ]: 33724 : else if (Token::Match(tok->tokAt(-2), "%var% ==|!= %var%"))
381 : 225 : ovar = tok->tokAt(-2)->variable();
382 [ + + ]: 33499 : else if (Token::Match(tok->tokAt(-2), "%var% =|+ %var% )|]|,|;|+"))
383 : 270 : ovar = tok->tokAt(-2)->variable();
384 [ + + ][ + + ]: 33949 : if (ovar && !ovar->isPointer() && !ovar->isArray() && Token::Match(ovar->typeStartToken(), "std :: string|wstring !!::"))
[ + - ][ + - ]
[ + + ]
385 : 225 : return true;
386 : :
387 : : // Check if it's NOT a pointer dereference.
388 : : // This is most useful in inconclusive checking
389 [ + + ]: 33724 : if (inconclusive) {
390 : : // Not a dereference..
391 [ + + ]: 7290 : if (Token::Match(tok, "%var% ="))
392 : 2295 : return false;
393 : :
394 : : // OK to delete a null
395 [ + + ][ + + ]: 4995 : if (Token::Match(tok->previous(), "delete %var%") || Token::Match(tok->tokAt(-3), "delete [ ] %var%"))
[ + + ]
396 : 90 : return false;
397 : :
398 : : // OK to check if pointer is null
399 : : // OK to take address of pointer
400 [ + + ]: 4905 : if (Token::Match(tok->previous(), "!|& %var%"))
401 : 855 : return false;
402 : :
403 : : // OK to check pointer in "= p ? : "
404 [ + + + - : 4140 : if (tok->next()->str() == "?" &&
+ - ][ + + ]
405 : 90 : (Token::Match(tok->previous(), "return|throw|;|{|}|:|[|(|,") || tok->previous()->isAssignmentOp()))
406 : 45 : return false;
407 : :
408 : : // OK to pass pointer to function
409 [ + + + - : 6255 : if (Token::Match(tok->previous(), "[(,] %var% [,)]") &&
+ + ][ + + ]
410 : 1125 : (!Token::Match(tok->previous(), "( %var%") ||
411 : 1125 : Token::Match(tok->tokAt(-2), "%var% ( %var%")))
412 : 1080 : return false;
413 : :
414 : : // Compare pointer
415 [ + + ]: 2925 : if (Token::Match(tok->previous(), "(|&&|%oror%|==|!= %var%"))
416 : 540 : return false;
417 [ + + ]: 2385 : if (Token::Match(tok, "%var% &&|%oror%|==|!=|)"))
418 : 45 : return false;
419 : :
420 : : // Taking address
421 [ + + ]: 2340 : if (Token::Match(tok->previous(), "return|= %var% ;"))
422 : 90 : return false;
423 : :
424 : : // (void)var
425 [ + + ]: 2250 : if (Token::Match(tok->previous(), "[{;}] %var% ;"))
426 : 45 : return false;
427 : :
428 : : // Shift pointer (e.g. to cout, but its no char* (see above))
429 [ + + ]: 2205 : if (Token::Match(tok->previous(), "<<|>> %var%"))
430 : 135 : return false;
431 : :
432 : : // unknown if it's a dereference
433 : 2070 : unknown = true;
434 : : }
435 : :
436 : : // assume that it's not a dereference (no false positives)
437 : 45337 : return false;
438 : : }
439 : :
440 : :
441 : : // check if function can assign pointer
442 : 1890 : bool CheckNullPointer::CanFunctionAssignPointer(const Token *functiontoken, unsigned int varid, bool& unknown)
443 : : {
444 [ + + ]: 1890 : if (Token::Match(functiontoken, "if|while|for|switch|sizeof|catch"))
445 : 765 : return false;
446 : :
447 : 1125 : unsigned int argumentNumber = 0;
448 [ + + ]: 1665 : for (const Token *arg = functiontoken->tokAt(2); arg; arg = arg->nextArgument()) {
449 [ + + ]: 1125 : if (Token::Match(arg, "%varid% [,)]", varid)) {
450 : 585 : const Function* func = functiontoken->function();
451 [ + + ]: 585 : if (!func) { // Unknown function
452 : 270 : unknown = true;
453 : 270 : return true; // assume that the function might assign the pointer
454 : : }
455 : :
456 : 315 : const Variable* var = func->getArgumentVar(argumentNumber);
457 [ - + ]: 315 : if (!var) { // Unknown variable
458 : 0 : unknown = true;
459 : 0 : return true;
460 [ + + ]: 315 : } else if (var->isReference()) // Assume every pointer passed by reference is assigned
461 : 45 : return true;
462 : : else
463 : 270 : return false;
464 : : }
465 : 540 : ++argumentNumber;
466 : : }
467 : :
468 : : // pointer is not passed
469 : 1890 : return false;
470 : : }
471 : :
472 : :
473 : :
474 : 12391 : void CheckNullPointer::nullPointerLinkedList()
475 : : {
476 : 12391 : const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
477 : :
478 : : // looping through items in a linked list in a inner loop.
479 : : // Here is an example:
480 : : // for (const Token *tok = tokens; tok; tok = tok->next) {
481 : : // if (tok->str() == "hello")
482 : : // tok = tok->next; // <- tok might become a null pointer!
483 : : // }
484 [ + + ]: 49674 : for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
485 : 37283 : const Token* const tok1 = i->classDef;
486 : : // search for a "for" scope..
487 [ + + ][ - + ]: 37283 : if (i->type != Scope::eFor || !tok1)
[ + + ]
488 : 36743 : continue;
489 : :
490 : : // is there any dereferencing occurring in the for statement
491 : 540 : const Token* end2 = tok1->linkAt(1);
492 [ + + ]: 7920 : for (const Token *tok2 = tok1->tokAt(2); tok2 != end2; tok2 = tok2->next()) {
493 : : // Dereferencing a variable inside the "for" parentheses..
494 [ + + ]: 7380 : if (Token::Match(tok2, "%var% . %var%")) {
495 : : // Is this variable a pointer?
496 : 270 : const Variable *var = tok2->variable();
497 [ + + ][ + + ]: 270 : if (!var || !var->isPointer())
[ + + ]
498 : 90 : continue;
499 : :
500 : : // Variable id for dereferenced variable
501 : 180 : const unsigned int varid(tok2->varId());
502 : :
503 [ + + ]: 180 : if (Token::Match(tok2->tokAt(-2), "%varid% ?", varid))
504 : 45 : continue;
505 : :
506 : : // Check usage of dereferenced variable in the loop..
507 [ + + ]: 360 : for (std::list<Scope*>::const_iterator j = i->nestedList.begin(); j != i->nestedList.end(); ++j) {
508 : 225 : Scope* scope = *j;
509 [ + + ]: 225 : if (scope->type != Scope::eWhile)
510 : 90 : continue;
511 : :
512 : : // TODO: are there false negatives for "while ( %varid% ||"
513 [ + - ]: 135 : if (Token::Match(scope->classDef->next(), "( %varid% &&|)", varid)) {
514 : : // Make sure there is a "break" or "return" inside the loop.
515 : : // Without the "break" a null pointer could be dereferenced in the
516 : : // for statement.
517 [ + - ]: 2160 : for (const Token *tok4 = scope->classStart; tok4; tok4 = tok4->next()) {
518 [ + + ]: 2025 : if (tok4 == i->classEnd) {
519 : 45 : nullPointerError(tok1, var->name(), scope->classDef);
520 : 45 : break;
521 : : }
522 : :
523 : : // There is a "break" or "return" inside the loop.
524 : : // TODO: there can be false negatives. There could still be
525 : : // execution paths that are not properly terminated
526 [ + + ][ + + ]: 1980 : else if (tok4->str() == "break" || tok4->str() == "return")
[ + + ]
527 : 90 : break;
528 : : }
529 : : }
530 : : }
531 : : }
532 : : }
533 : : }
534 : 12391 : }
535 : :
536 : 11655 : void CheckNullPointer::nullPointerStructByDeRefAndChec()
537 : : {
538 : : // Dereferencing a struct pointer and then checking if it's NULL..
539 : 11655 : const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
540 : :
541 : : // skipvar: don't check vars that has been tested against null already
542 : 11655 : std::set<unsigned int> skipvar;
543 [ + - ]: 11655 : skipvar.insert(0);
544 : :
545 : 11655 : const std::size_t functions = symbolDatabase->functionScopes.size();
546 [ + + ]: 23580 : for (std::size_t i = 0; i < functions; ++i) {
547 : 11925 : const Scope * scope = symbolDatabase->functionScopes[i];
548 [ + - ][ - + ]: 11925 : if (scope->function == 0 || !scope->function->hasBody) // We only look for functions with a body
549 : 0 : continue;
550 [ + + ]: 239985 : for (const Token *tok1 = scope->classStart; tok1 != scope->classEnd; tok1 = tok1->next()) {
551 : : // Checking if some pointer is null.
552 : : // then add the pointer to skipvar => is it known that it isn't NULL
553 [ + - ][ + + ]: 228060 : if (Token::Match(tok1, "if|while ( !| %var% )")) {
554 [ + - ]: 6615 : tok1 = tok1->tokAt(2);
555 [ + - ][ + + ]: 6615 : if (tok1->str() == "!")
556 : 3465 : tok1 = tok1->next();
557 [ + - ]: 6615 : skipvar.insert(tok1->varId());
558 : 6615 : continue;
559 [ + - ][ + + ]: 442530 : } else if (Token::Match(tok1, "( ! %var% %oror%") ||
[ + + ][ + + ]
560 [ + - ]: 221085 : Token::Match(tok1, "( %var% &&")) {
561 : : // TODO: there are false negatives caused by this. The
562 : : // variable should be removed from skipvar after the
563 : : // condition
564 : 1215 : tok1 = tok1->next();
565 [ + - ][ + + ]: 1215 : if (tok1->str() == "!")
566 : 360 : tok1 = tok1->next();
567 [ + - ]: 1215 : skipvar.insert(tok1->varId());
568 : 1215 : continue;
569 : : }
570 : :
571 : 220230 : bool inconclusive = false;
572 : :
573 : : /**
574 : : * @todo There are lots of false negatives here. A dereference
575 : : * is only investigated if a few specific conditions are met.
576 : : */
577 : :
578 : : // dereference in assignment
579 [ + - ][ + + ]: 220230 : if (Token::Match(tok1, "[;{}] %var% . %var%")) {
580 : 1800 : tok1 = tok1->next();
581 [ + - ][ + - ]: 1800 : if (tok1->strAt(3) == "(") {
[ + + ]
582 [ + + ]: 1125 : if (!_settings->inconclusive)
583 : 720 : continue;
584 : 405 : inconclusive = true;
585 : : }
586 : : }
587 : :
588 : : // dereference in assignment
589 [ + - ][ + + ]: 218430 : else if (Token::Match(tok1, "[{};] %var% = %var% . %var%")) {
590 [ + - ][ + - ]: 1485 : if (tok1->strAt(1) == tok1->strAt(3))
[ + - ][ + + ]
591 : 990 : continue;
592 [ + - ]: 495 : tok1 = tok1->tokAt(3);
593 : : }
594 : :
595 : : // dereference in condition
596 [ + - ][ + + ]: 216945 : else if (Token::Match(tok1, "if ( !| %var% .")) {
597 [ + - ]: 405 : tok1 = tok1->tokAt(2);
598 [ + - ][ + + ]: 405 : if (tok1->str() == "!")
599 : 90 : tok1 = tok1->next();
600 : : }
601 : :
602 : : // dereference in function call (but not sizeof|decltype)
603 [ + - ][ + - ]: 432765 : else if ((Token::Match(tok1->tokAt(-2), "%var% ( %var% . %var%") && !Token::Match(tok1->tokAt(-2), "sizeof|decltype ( %var% . %var%")) ||
[ + + ][ + - ]
[ + - ][ + + ]
[ + + ][ + + ]
604 [ + - ]: 216225 : Token::Match(tok1->previous(), ", %var% . %var%")) {
605 : : // Is the function return value taken by the pointer?
606 : 360 : bool assignment = false;
607 : 360 : const unsigned int varid1(tok1->varId());
608 [ - + ]: 360 : if (varid1 == 0)
609 : 0 : continue;
610 : 360 : const Token *tok2 = tok1->previous();
611 [ + - ][ + - ]: 2025 : while (tok2 && !Token::Match(tok2, "[;{}]")) {
[ + + ][ + + ]
612 [ + - ][ + + ]: 1755 : if (Token::Match(tok2, "%varid% =", varid1)) {
613 : 90 : assignment = true;
614 : 90 : break;
615 : : }
616 : 1665 : tok2 = tok2->previous();
617 : : }
618 [ + + ]: 360 : if (assignment)
619 : 90 : continue;
620 : :
621 : : // Is the dereference checked with a previous &&
622 : 270 : bool checked = false;
623 [ + - ][ + - ]: 900 : for (tok2 = tok1->tokAt(-2); tok2; tok2 = tok2->previous()) {
624 [ + - ][ + + ]: 900 : if (Token::Match(tok2, "[,(;{}]"))
625 : 225 : break;
626 [ + - ][ - + ]: 675 : else if (tok2->str() == ")")
627 : 0 : tok2 = tok2->link();
628 [ + - ][ + + ]: 675 : else if (Token::Match(tok2, "%varid% &&", varid1)) {
629 : 45 : checked = true;
630 : 45 : break;
631 : : }
632 : : }
633 [ + + ]: 270 : if (checked)
634 : 45 : continue;
635 : : }
636 : :
637 : : // Goto next token
638 : : else {
639 : 216180 : continue;
640 : : }
641 : :
642 : : // struct dereference was found - investigate if it is later
643 : : // checked that it is not NULL
644 : 2205 : const unsigned int varid1(tok1->varId());
645 [ + - ][ + - ]: 2205 : if (skipvar.find(varid1) != skipvar.end())
[ + + ]
646 : 765 : continue;
647 : :
648 : : // name of struct pointer
649 : 1440 : const std::string& varname(tok1->str());
650 : :
651 : : // is pointer local?
652 : 1440 : bool isLocal = false;
653 : 1440 : const Variable *var = tok1->variable();
654 [ - + ]: 1440 : if (!var)
655 : 0 : continue;
656 [ + - ][ + + ]: 1440 : if (var->isLocal() || var->isArgument())
[ + + ][ + + ]
657 : 1395 : isLocal = true;
658 : :
659 : : // member function may or may not nullify the pointer if it's global (#2647)
660 [ + + ]: 1440 : if (!isLocal) {
661 : 45 : const Token *tok2 = tok1;
662 [ + - ][ + + ]: 90 : while (Token::Match(tok2, "%var% ."))
663 [ + - ]: 45 : tok2 = tok2->tokAt(2);
664 [ + - ][ - + ]: 45 : if (Token::Match(tok2,"%var% ("))
665 : 0 : continue;
666 : : }
667 : :
668 : : // count { and } using tok2
669 : 1440 : const Token* const end2 = tok1->scope()->classEnd;
670 [ + - ][ + + ]: 9765 : for (const Token *tok2 = tok1->tokAt(3); tok2 != end2; tok2 = tok2->next()) {
671 : 9315 : bool unknown = false;
672 : :
673 : : // label / ?:
674 [ + - ][ + + ]: 9315 : if (tok2->str() == ":")
675 : 90 : break;
676 : :
677 : : // function call..
678 [ + - ][ + + ]: 9225 : else if (Token::Match(tok2, "[;{}] %var% (") && CanFunctionAssignPointer(tok2->next(), varid1, unknown)) {
[ + - ][ + + ]
[ + + ]
679 [ + + ][ - + ]: 90 : if (!_settings->inconclusive || !unknown)
680 : 45 : break;
681 : 45 : inconclusive = true;
682 : : }
683 : :
684 : : // Reassignment of the struct
685 [ + + ]: 9135 : else if (tok2->varId() == varid1) {
686 [ + - ][ + + ]: 450 : if (tok2->next()->str() == "=") {
687 : : // Avoid false positives when there is 'else if'
688 : : // TODO: can this be handled better?
689 [ + - ][ + - ]: 90 : if (tok1->strAt(-2) == "if")
[ + + ]
690 [ + - ]: 45 : skipvar.insert(varid1);
691 : 90 : break;
692 : : }
693 [ + - ][ + - ]: 360 : if (Token::Match(tok2->tokAt(-2), "[,(] &"))
[ + + ]
694 : 45 : break;
695 : : }
696 : :
697 : : // Loop..
698 : : /** @todo don't bail out if the variable is not used in the loop */
699 [ + - ][ + + ]: 8685 : else if (tok2->str() == "do")
700 : 45 : break;
701 : :
702 : : // return/break at base level => stop checking
703 [ + + ][ + - ]: 8640 : else if (tok2->scope()->classEnd == end2 && (tok2->str() == "return" || tok2->str() == "break"))
[ + - ][ + - ]
[ + + ][ + + ]
704 : 45 : break;
705 : :
706 : : // Function call: If the pointer is not a local variable it
707 : : // might be changed by the call.
708 [ + - ][ + + ]: 9630 : else if (Token::Match(tok2, "[;{}] %var% (") &&
[ + + ][ + + ]
[ + + ]
709 [ + - ][ + - ]: 1035 : Token::simpleMatch(tok2->linkAt(2), ") ;") && !isLocal) {
710 : 45 : break;
711 : : }
712 : :
713 : : // Check if pointer is null.
714 : : // TODO: false negatives for "if (!p || .."
715 [ + + ][ + - ]: 8550 : else if (!tok2->isExpandedMacro() && Token::Match(tok2, "if ( !| %varid% )|&&", varid1)) {
[ + + ][ + + ]
716 : : // Is this variable a pointer?
717 [ + + ]: 585 : if (var->isPointer())
718 [ + - ]: 540 : nullPointerError(tok1, varname, tok2, inconclusive);
719 : 585 : break;
720 : : }
721 : : }
722 : : }
723 : 11655 : }
724 : 11655 : }
725 : :
726 : 11655 : void CheckNullPointer::nullPointerByDeRefAndChec()
727 : : {
728 : 11655 : const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
729 : :
730 : : // Dereferencing a pointer and then checking if it's NULL..
731 : : // This check will first scan for the check. And then scan backwards
732 : : // from the check, searching for dereferencing.
733 [ + + ]: 45945 : for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
734 : : // TODO: false negatives.
735 : : // - logical operators
736 : 34290 : const Token* tok = i->classDef;
737 [ + + ][ + + ]: 50760 : if ((i->type == Scope::eIf || i->type == Scope::eElseIf || i->type == Scope::eWhile) &&
[ + + ][ + -
+ + + + ]
[ + + ]
738 : 16470 : tok && Token::Match(tok, "else| %var% ( !| %var% )|%oror%|&&") && !tok->next()->isExpandedMacro()) {
739 : :
740 [ - + ]: 7515 : if (tok->str() == "else")
741 : 0 : tok = tok->next();
742 : :
743 : 7515 : const Token * vartok = tok->tokAt(2);
744 [ + + ]: 7515 : if (vartok->str() == "!")
745 : 3645 : vartok = vartok->next();
746 : :
747 : 7515 : const Variable *var = vartok->variable();
748 : : // Check that variable is a pointer..
749 [ + + ][ + + ]: 7515 : if (!var || !var->isPointer())
[ + + ]
750 : 990 : continue;
751 : :
752 : : // Variable id for pointer
753 : 6525 : const unsigned int varid(vartok->varId());
754 : :
755 : : // Name of pointer
756 : 6525 : const std::string& varname(vartok->str());
757 : :
758 : 6525 : const Token * const decltok = var->nameToken();
759 : 6525 : bool inconclusive = false;
760 : :
761 [ + - ][ + + ]: 30330 : for (const Token *tok1 = tok->previous(); tok1 && tok1 != decltok; tok1 = tok1->previous()) {
[ + + ]
762 [ + + ][ + + ]: 23805 : if (tok1->str() == ")" && Token::Match(tok1->link()->previous(), "%var% (")) {
[ + + ]
763 : 1845 : const Token *tok2 = tok1->link();
764 [ + - ][ + + ]: 7290 : while (tok2 && !Token::Match(tok2, "[;{}?:]"))
[ + + ]
765 : 5445 : tok2 = tok2->previous();
766 [ + + ]: 1845 : if (Token::Match(tok2, "[?:]"))
767 : 45 : break;
768 [ + + ]: 1800 : if (Token::Match(tok2->next(), "%varid% = %var%", varid))
769 : 270 : break;
770 : :
771 [ + + ]: 1530 : if (Token::Match(tok2->next(), "while ( %varid%", varid))
772 : 45 : break;
773 : :
774 [ + + + + ]: 2790 : if (Token::Match(tok1->link(), "( ! %varid% %oror%", varid) ||
[ + + ]
775 : 1305 : Token::Match(tok1->link(), "( %varid% &&", varid)) {
776 : 270 : tok1 = tok1->link();
777 : 270 : continue;
778 : : }
779 : :
780 [ + + ]: 1215 : if (Token::simpleMatch(tok1->link()->previous(), "sizeof (")) {
781 : 180 : tok1 = tok1->link()->previous();
782 : 180 : continue;
783 : : }
784 : :
785 [ + + ]: 1035 : if (Token::Match(tok2->next(), "%var% ( %varid% ,", varid)) {
786 : 45 : std::list<const Token *> varlist;
787 [ + - ]: 45 : parseFunctionCall(*(tok2->next()), varlist, 0);
788 [ + - ][ + - ]: 45 : if (!varlist.empty() && varlist.front() == tok2->tokAt(3)) {
[ + - ][ + - ]
[ + - ]
789 [ + - ][ + - ]: 45 : nullPointerError(tok2->tokAt(3), varname, tok, inconclusive);
790 : : break;
791 [ - + ]: 45 : }
792 : : }
793 : :
794 : : // Passing pointer as parameter..
795 [ + + ]: 990 : if (Token::Match(tok2->next(), "%type% (")) {
796 : 765 : bool unknown = false;
797 [ + + ]: 765 : if (CanFunctionAssignPointer(tok2->next(), varid, unknown)) {
798 [ + + ][ + + ]: 225 : if (!_settings->inconclusive || !unknown)
799 : 135 : break;
800 : 90 : inconclusive = true;
801 : : }
802 : : }
803 : :
804 : : // calling unknown function => it might initialize the pointer
805 [ + + ][ + + ]: 855 : if (!(var->isLocal() || var->isArgument()))
[ + + ]
806 : 135 : break;
807 : : }
808 : :
809 [ + + ]: 22680 : if (tok1->str() == "break")
810 : 45 : break;
811 : :
812 [ + + ]: 22635 : if (tok1->varId() == varid) {
813 : : // Don't write warning if the dereferencing is
814 : : // guarded by ?: or &&
815 : 2565 : const Token *tok2 = tok1->previous();
816 [ + - ][ + + ]: 2565 : if (tok2 && (tok2->isArithmeticalOp() || tok2->str() == "(")) {
[ + + ][ + + ]
817 [ + - ][ + + ]: 3240 : while (tok2 && !Token::Match(tok2, "[;{}?:]")) {
[ + + ]
818 [ + + ]: 2160 : if (tok2->str() == ")") {
819 : 45 : tok2 = tok2->link();
820 [ + - ]: 45 : if (Token::Match(tok2, "( %varid% =", varid)) {
821 : 45 : tok2 = tok2->next();
822 : 45 : break;
823 : : }
824 : : }
825 : : // guarded by &&
826 [ + + ][ + + ]: 2115 : if (tok2->varId() == varid && tok2->next()->str() == "&&")
[ + + ]
827 : 45 : break;
828 : 2070 : tok2 = tok2->previous();
829 : : }
830 : : }
831 [ + - ][ + + ]: 2565 : if (!tok2 || Token::Match(tok2, "[?:]") || tok2->varId() == varid)
[ + + ][ + + ]
832 : 315 : continue;
833 : :
834 : : // unknown : this is set by isPointerDeRef if it is
835 : : // uncertain
836 : 2250 : bool unknown = _settings->inconclusive;
837 : :
838 : : // reassign : is the pointer reassigned like this:
839 : : // tok = tok->next();
840 : 2250 : bool reassign = false;
841 [ + + ]: 2250 : if (Token::Match(tok1->previous(), "= %varid% .", varid)) {
842 : 225 : const Token *back = tok1->tokAt(-2);
843 [ + - ]: 630 : while (back) {
844 [ + + ]: 405 : if (back->varId() == varid) {
845 : 180 : reassign = true;
846 : 180 : break;
847 : : }
848 [ + + ]: 225 : if (Token::Match(back, "[{};,(]")) {
849 : 45 : break;
850 : : }
851 : 180 : back = back->previous();
852 : : }
853 [ + + ]: 2025 : } else if (Token::Match(tok1->tokAt(-4), "%varid% = ( * %varid%", varid)) {
854 : 45 : reassign = true;
855 [ + + ]: 1980 : } else if (Token::Match(tok1->tokAt(-3), "%varid% = * %varid%", varid)) {
856 : 45 : reassign = true;
857 : : }
858 : :
859 [ + + ]: 2250 : if (reassign) {
860 : 270 : break;
861 [ + + + - ]: 2025 : } else if (Token::simpleMatch(tok1->tokAt(-2), "* )") &&
[ + + ]
862 : 45 : Token::Match(tok1->linkAt(-1)->tokAt(-2), "%varid% = (", tok1->varId())) {
863 : 45 : break;
864 [ - + # # ]: 1935 : } else if (Token::simpleMatch(tok1->tokAt(-3), "* ) (") &&
[ - + ]
865 : 0 : Token::Match(tok1->linkAt(-2)->tokAt(-2), "%varid% = (", tok1->varId())) {
866 : 0 : break;
867 [ + + ]: 1935 : } else if (Token::Match(tok1->previous(), "&&|%oror%")) {
868 : 45 : break;
869 [ - + ]: 1890 : } else if (Token::Match(tok1->tokAt(-2), "&&|%oror% !")) {
870 : 0 : break;
871 [ + + ]: 1890 : } else if (CheckNullPointer::isPointerDeRef(tok1, unknown)) {
872 : 720 : nullPointerError(tok1, varname, tok, inconclusive);
873 : 720 : break;
874 [ + + ]: 1170 : } else if (tok1->strAt(-1) == "&") {
875 : 90 : break;
876 [ + + ]: 1080 : } else if (tok1->strAt(1) == "=") {
877 : 495 : break;
878 : : }
879 : : }
880 : :
881 [ + + + + ]: 36855 : else if (tok1->str() == "{" ||
[ + + ]
882 : 16785 : tok1->str() == "}")
883 : 3870 : break;
884 : :
885 : : // label..
886 [ + + ]: 16200 : else if (Token::Match(tok1, "%type% :"))
887 : 45 : break;
888 : : }
889 : : }
890 : : }
891 : 11655 : }
892 : :
893 : 11655 : void CheckNullPointer::nullPointerByCheckAndDeRef()
894 : : {
895 : 11655 : const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
896 : :
897 : : // Check if pointer is NULL and then dereference it..
898 [ + + ]: 45945 : for (std::list<Scope>::const_iterator i = symbolDatabase->scopeList.begin(); i != symbolDatabase->scopeList.end(); ++i) {
899 [ + + ][ + + ]: 34290 : if (i->type != Scope::eIf && i->type != Scope::eElseIf && i->type != Scope::eWhile)
[ + + ][ + + ]
900 : 25470 : continue;
901 [ + - ][ + + ]: 8820 : if (!i->classDef || i->classDef->isExpandedMacro())
[ + + ]
902 : 135 : continue;
903 : :
904 [ + + ]: 8685 : const Token* const tok = i->type != Scope::eElseIf ? i->classDef->next() : i->classDef->tokAt(2);
905 : : // TODO: investigate false negatives:
906 : : // - handle "while"?
907 : : // - if there are logical operators
908 : : // - if (x) { } else { ... }
909 : :
910 : : // If the if-body ends with a unknown macro then bailout
911 [ + + ][ + + ]: 8685 : if (Token::Match(i->classEnd->tokAt(-3), "[;{}] %var% ;") && i->classEnd->tokAt(-2)->isUpperCaseName())
[ + + ]
912 : 45 : continue;
913 : :
914 : : // vartok : token for the variable
915 : 8640 : const Token *vartok = 0;
916 : 8640 : const Token *checkConditionStart = 0;
917 [ + + ]: 8640 : if (Token::Match(tok, "( ! %var% )|&&")) {
918 : 3510 : vartok = tok->tokAt(2);
919 : 3510 : checkConditionStart = vartok->next();
920 [ + + ]: 5130 : } else if (Token::Match(tok, "( %var% )|&&")) {
921 : 3780 : vartok = tok->next();
922 [ + + ]: 1350 : } else if (Token::Match(tok, "( ! ( %var% =")) {
923 : 90 : vartok = tok->tokAt(3);
924 [ + + ]: 90 : if (Token::simpleMatch(tok->linkAt(2), ") &&"))
925 : 45 : checkConditionStart = tok->linkAt(2);
926 : : } else
927 : 1260 : continue;
928 : :
929 : : // Check if variable is a pointer
930 : 7380 : const Variable *var = vartok->variable();
931 [ + + ][ + + ]: 7380 : if (!var || !var->isPointer())
[ + + ]
932 : 990 : continue;
933 : :
934 : : // variable id for pointer
935 : 6390 : const unsigned int varid(vartok->varId());
936 : :
937 : 6390 : const Scope* declScope = &*i;
938 [ + - ][ + + ]: 13140 : while (declScope->nestedIn && var->scope() != declScope && declScope->type != Scope::eFunction)
[ + + ][ + + ]
939 : 6750 : declScope = declScope->nestedIn;
940 : :
941 [ + + ]: 6390 : if (Token::Match(vartok->next(), "&& ( %varid% =", varid))
942 : 90 : continue;
943 : :
944 : : // Name and line of the pointer
945 : 6300 : const std::string &pointerName = vartok->str();
946 : :
947 : : // Check the condition (eg. ( !x && x->i )
948 [ + + ]: 6300 : if (checkConditionStart) {
949 : 3285 : const Token * const conditionEnd = tok->link();
950 [ + + ]: 4005 : for (const Token *tok2 = checkConditionStart; tok2 != conditionEnd; tok2 = tok2->next()) {
951 : : // If we hit a || operator, abort
952 [ + + ]: 720 : if (tok2->str() == "||")
953 : 45 : break;
954 : :
955 : : // Pointer is used
956 : 675 : bool unknown = _settings->inconclusive;
957 [ + + ][ - + ]: 675 : if (tok2->varId() == varid && (isPointerDeRef(tok2, unknown) || unknown)) {
[ # # ][ + + ]
958 : 135 : nullPointerError(tok2, pointerName, vartok, unknown);
959 : 135 : break;
960 : : }
961 : : }
962 : : }
963 : :
964 : : // start token = inside the if-body
965 : 6300 : const Token *tok1 = i->classStart;
966 : :
967 [ + + ]: 6300 : if (Token::Match(tok, "( %var% )|&&")) {
968 : : // start token = first token after the if/while body
969 : 2970 : tok1 = i->classEnd->next();
970 [ - + ]: 2970 : if (!tok1)
971 : 0 : continue;
972 : : }
973 : :
974 : 6300 : int indentlevel = 0;
975 : :
976 : : // Set to true if we would normally bail out the check.
977 : 6300 : bool inconclusive = false;
978 : :
979 : : // Count { and } for tok2
980 [ + + ]: 24840 : for (const Token *tok2 = tok1; tok2 != declScope->classEnd; tok2 = tok2->next()) {
981 [ + + ]: 20925 : if (tok2->str() == "{")
982 : 3690 : ++indentlevel;
983 [ + + ]: 17235 : else if (tok2->str() == "}") {
984 [ + + ]: 2835 : if (indentlevel == 0) {
985 [ + + ]: 180 : if (_settings->inconclusive)
986 : 45 : inconclusive = true;
987 : : else
988 : 135 : break;
989 : : }
990 : 2700 : --indentlevel;
991 : :
992 : : // calling exit function?
993 : 2700 : bool unknown = false;
994 [ + + ]: 2700 : if (_tokenizer->IsScopeNoReturn(tok2, &unknown)) {
995 [ + - ][ + - ]: 45 : if (_settings->inconclusive && unknown)
996 : 45 : inconclusive = true;
997 : : else
998 : 0 : break;
999 : : }
1000 : :
1001 [ + + ]: 2700 : if (indentlevel <= 0) {
1002 : : // skip all "else" blocks because they are not executed in this execution path
1003 [ + + ]: 2655 : while (Token::simpleMatch(tok2, "} else if ("))
1004 : 45 : tok2 = tok2->linkAt(3)->linkAt(1);
1005 [ + + ]: 2610 : if (Token::simpleMatch(tok2, "} else {"))
1006 : 45 : tok2 = tok2->linkAt(2);
1007 : : }
1008 : : }
1009 : :
1010 [ + + ][ + + ]: 20790 : if (tok2->str() == "return" || tok2->str() == "throw") {
[ + + ]
1011 : 810 : bool unknown = _settings->inconclusive;
1012 [ + - ][ + + ]: 2520 : for (; tok2 && tok2->str() != ";"; tok2 = tok2->next()) {
[ + + ]
1013 [ + + ]: 1755 : if (tok2->varId() == varid) {
1014 [ + + ]: 180 : if (CheckNullPointer::isPointerDeRef(tok2, unknown))
1015 : 135 : nullPointerError(tok2, pointerName, vartok, inconclusive);
1016 [ - + ]: 45 : else if (unknown)
1017 : 0 : nullPointerError(tok2, pointerName, vartok, true);
1018 [ + + ]: 180 : if (Token::Match(tok2, "%var% ?"))
1019 : 45 : break;
1020 : : }
1021 : : }
1022 : 810 : break;
1023 : : }
1024 : :
1025 : : // Bailout for "if".
1026 [ + + ]: 19980 : if (tok2->str() == "if") {
1027 [ + + ]: 315 : if (_settings->inconclusive)
1028 : 90 : inconclusive = true;
1029 : : else
1030 : 225 : break;
1031 : : }
1032 : :
1033 [ + + ]: 19755 : if (Token::Match(tok2, "goto|continue|break|switch|for"))
1034 : 315 : break;
1035 : :
1036 : : // parameters to sizeof are not dereferenced
1037 [ + + ]: 19440 : if (Token::Match(tok2, "decltype|sizeof")) {
1038 [ + + ]: 180 : if (tok2->strAt(1) != "(")
1039 : 45 : tok2 = tok2->next();
1040 : : else
1041 : 135 : tok2 = tok2->next()->link();
1042 : 180 : continue;
1043 : : }
1044 : :
1045 : : // function call, check if pointer is dereferenced
1046 [ + + ][ + + ]: 19260 : if (Token::Match(tok2, "%var% (") && !Token::Match(tok2, "if|while")) {
[ + + ]
1047 : 675 : std::list<const Token *> vars;
1048 [ + - ]: 675 : parseFunctionCall(*tok2, vars, 0);
1049 [ + - ][ + - ]: 720 : for (std::list<const Token *>::const_iterator it = vars.begin(); it != vars.end(); ++it) {
[ + + ]
1050 [ + - ][ + + ]: 135 : if (Token::Match(*it, "%varid% [,)]", varid)) {
1051 [ + - ]: 90 : nullPointerError(*it, pointerName, vartok, inconclusive);
1052 : 90 : break;
1053 : : }
1054 : 675 : }
1055 : : }
1056 : :
1057 : : // calling unknown function (abort/init)..
1058 [ + + + + : 19125 : else if (Token::simpleMatch(tok2, ") ;") &&
+ - ][ + + ]
1059 : 495 : (Token::Match(tok2->link()->tokAt(-2), "[;{}.] %var% (") ||
1060 : 45 : Token::Match(tok2->link()->tokAt(-5), "[;{}] ( * %var% ) ("))) {
1061 : : // noreturn function?
1062 : 495 : bool unknown = false;
1063 [ + + ]: 495 : if (_tokenizer->IsScopeNoReturn(tok2->tokAt(2), &unknown)) {
1064 [ + + ][ + + ]: 405 : if (!unknown || !_settings->inconclusive) {
1065 : 270 : break;
1066 : : }
1067 : 135 : inconclusive = _settings->inconclusive;
1068 : : }
1069 : :
1070 : : // init function (global variables)
1071 [ + - ][ + - ]: 225 : if (!var || !(var->isLocal() || var->isArgument()))
[ + + ][ + + ]
1072 : 45 : break;
1073 : : }
1074 : :
1075 [ + + ]: 18945 : if (tok2->varId() == varid) {
1076 : : // unknown: this is set to true by isPointerDeRef if
1077 : : // the function fails to determine if there
1078 : : // is a dereference or not
1079 : 1440 : bool unknown = _settings->inconclusive;
1080 : :
1081 [ + - ]: 1440 : if (Token::Match(tok2->previous(), "[;{}=] %var% = 0 ;"))
1082 : : ;
1083 : :
1084 [ + + ]: 1440 : else if (CheckNullPointer::isPointerDeRef(tok2, unknown))
1085 : 720 : nullPointerError(tok2, pointerName, vartok, inconclusive);
1086 : :
1087 [ + + ][ + + ]: 720 : else if (unknown && _settings->inconclusive)
1088 : 135 : nullPointerError(tok2, pointerName, vartok, true);
1089 : :
1090 : : else
1091 : 1440 : break;
1092 : : }
1093 : : }
1094 : : }
1095 : 11655 : }
1096 : :
1097 : :
1098 : 12391 : void CheckNullPointer::nullPointer()
1099 : : {
1100 : 12391 : nullPointerLinkedList();
1101 : :
1102 [ + - ][ + - ]: 12391 : if (_settings->isEnabled("warning")) {
[ + - ][ + + ]
1103 : 11655 : nullPointerStructByDeRefAndChec();
1104 : 11655 : nullPointerByDeRefAndChec();
1105 : 11655 : nullPointerByCheckAndDeRef();
1106 : : }
1107 : :
1108 : 12391 : nullPointerDefaultArgument();
1109 : 12391 : }
1110 : :
1111 : : /** Dereferencing null constant (simplified token list) */
1112 : 12391 : void CheckNullPointer::nullConstantDereference()
1113 : : {
1114 : 12391 : const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
1115 : :
1116 : 12391 : const std::size_t functions = symbolDatabase->functionScopes.size();
1117 [ + + ]: 25052 : for (std::size_t i = 0; i < functions; ++i) {
1118 : 12661 : const Scope * scope = symbolDatabase->functionScopes[i];
1119 [ + - ][ - + ]: 12661 : if (scope->function == 0 || !scope->function->hasBody) // We only look for functions with a body
1120 : 0 : continue;
1121 : :
1122 : 12661 : const Token *tok = scope->classStart;
1123 : :
1124 [ + - ][ + + ]: 12661 : if (scope->function && (scope->function->type == Function::eConstructor || scope->function->type == Function::eCopyConstructor))
[ - + ]
1125 : 90 : tok = scope->function->token; // Check initialization list
1126 : :
1127 [ + + ]: 268235 : for (; tok != scope->classEnd; tok = tok->next()) {
1128 [ + + ]: 255574 : if (Token::Match(tok, "sizeof|decltype|typeid ("))
1129 : 585 : tok = tok->next()->link();
1130 : :
1131 [ + + ]: 254989 : else if (Token::simpleMatch(tok, "* 0")) {
1132 [ + + ][ + - ]: 450 : if (Token::Match(tok->previous(), "return|throw|;|{|}|:|[|(|,") || tok->previous()->isOp()) {
[ + - ]
1133 : 450 : nullPointerError(tok);
1134 : : }
1135 : : }
1136 : :
1137 [ + + ][ - + ]: 254539 : else if (Token::Match(tok, "0 [") && (tok->previous()->str() != "&" || !Token::Match(tok->next()->link()->next(), "[.(]")))
[ # # ][ + + ]
1138 : 90 : nullPointerError(tok);
1139 : :
1140 [ + + ][ + + ]: 254449 : else if (Token::Match(tok->previous(), "!!. %var% (") && (tok->previous()->str() != "::" || tok->strAt(-2) == "std")) {
[ + + ][ + + ]
1141 [ + + ][ + + ]: 16371 : if (Token::simpleMatch(tok->tokAt(2), "0 )") && tok->varId()) { // constructor call
[ + + ]
1142 : 135 : const Variable *var = tok->variable();
1143 [ + - ][ + - ]: 135 : if (var && !var->isPointer() && !var->isArray() && Token::Match(var->typeStartToken(), "std :: string|wstring !!::"))
[ + - ][ + - ]
[ + - ]
1144 : 135 : nullPointerError(tok);
1145 : : } else { // function call
1146 : 16236 : std::list<const Token *> var;
1147 [ + - ]: 16236 : parseFunctionCall(*tok, var, 0);
1148 : :
1149 : : // is one of the var items a NULL pointer?
1150 [ + - ][ + - ]: 18126 : for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it) {
[ + + ]
1151 [ + - ][ + + ]: 1890 : if (Token::Match(*it, "0 [,)]")) {
1152 [ + - ]: 630 : nullPointerError(*it);
1153 : : }
1154 : 16236 : }
1155 : : }
1156 [ + + ]: 238078 : } else if (Token::Match(tok, "std :: string|wstring ( 0 )"))
1157 : 45 : nullPointerError(tok);
1158 : :
1159 [ - + ]: 238033 : else if (Token::simpleMatch(tok->previous(), ">> 0")) { // Only checking input stream operations is safe here, because otherwise 0 can be an integer as well
1160 : 0 : const Token* tok2 = tok->previous(); // Find start of statement
1161 [ # # ]: 0 : for (; tok2; tok2 = tok2->previous()) {
1162 [ # # ]: 0 : if (Token::Match(tok2->previous(), ";|{|}|:"))
1163 : 0 : break;
1164 : : }
1165 [ # # ]: 0 : if (Token::simpleMatch(tok2, "std :: cin"))
1166 : 0 : nullPointerError(tok);
1167 [ # # ][ # # ]: 0 : if (tok2 && tok2->varId() != 0) {
[ # # ]
1168 : 0 : const Variable *var = tok2->variable();
1169 [ # # ][ # # ]: 0 : if (var && Token::Match(var->typeStartToken(), "std :: istream|ifstream|istringstream|wistringstream|stringstream|wstringstream|fstream|iostream"))
[ # # ]
1170 : 0 : nullPointerError(tok);
1171 : : }
1172 : : }
1173 : :
1174 : 255574 : const Variable *ovar = 0;
1175 [ + + ]: 255574 : if (Token::Match(tok, "0 ==|!= %var%"))
1176 : 45 : ovar = tok->tokAt(2)->variable();
1177 [ + + ]: 255529 : else if (Token::Match(tok, "%var% ==|!= 0"))
1178 : 45 : ovar = tok->variable();
1179 [ + + ]: 255484 : else if (Token::Match(tok, "%var% =|+ 0 )|]|,|;|+"))
1180 : 5940 : ovar = tok->variable();
1181 [ + + ][ + + ]: 255574 : if (ovar && !ovar->isPointer() && !ovar->isArray() && Token::Match(ovar->typeStartToken(), "std :: string|wstring !!::"))
[ + - ][ + + ]
[ + + ]
1182 : 135 : nullPointerError(tok);
1183 : : }
1184 : : }
1185 : 12391 : }
1186 : :
1187 : :
1188 : : /**
1189 : : * @brief Does one part of the check for nullPointer().
1190 : : * -# default argument that sets a pointer to 0
1191 : : * -# dereference pointer
1192 : : */
1193 : 12391 : void CheckNullPointer::nullPointerDefaultArgument()
1194 : : {
1195 : 12391 : const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
1196 : 12391 : const std::size_t functions = symbolDatabase->functionScopes.size();
1197 [ + + ]: 25052 : for (std::size_t i = 0; i < functions; ++i) {
1198 : 12661 : const Scope * scope = symbolDatabase->functionScopes[i];
1199 [ + - ][ - + ]: 12661 : if (scope->function == 0 || !scope->function->hasBody) // We only look for functions with a body
1200 : 0 : continue;
1201 : :
1202 : : // Scan the argument list for default arguments that are pointers and
1203 : : // which default to a NULL pointer if no argument is specified.
1204 : 12661 : std::set<unsigned int> pointerArgs;
1205 [ + + ]: 50972 : for (const Token *tok = scope->function->arg; tok != scope->function->arg->link(); tok = tok->next()) {
1206 : :
1207 [ + - ][ + + ]: 38311 : if (Token::Match(tok, "%var% = 0 ,|)") && tok->varId() != 0) {
[ + - ][ + + ]
1208 : 675 : const Variable *var = tok->variable();
1209 [ + - ][ + - ]: 675 : if (var && var->isPointer())
[ + - ]
1210 [ + - ]: 675 : pointerArgs.insert(tok->varId());
1211 : : }
1212 : : }
1213 : :
1214 : : // Report an error if any of the default-NULL arguments are dereferenced
1215 [ + - ][ + + ]: 12661 : if (!pointerArgs.empty()) {
1216 : 675 : bool unknown = _settings->inconclusive;
1217 [ + + ]: 7200 : for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
1218 : : // If we encounter a possible NULL-pointer check, skip over its body
1219 [ + - ][ + + ]: 6525 : if (Token::simpleMatch(tok, "if ( ")) {
1220 : 225 : bool dependsOnPointer = false;
1221 : 225 : const Token *endOfCondition = tok->next()->link();
1222 [ - + ]: 225 : if (!endOfCondition)
1223 : 0 : continue;
1224 : :
1225 : : const Token *startOfIfBlock =
1226 [ + - ][ + - ]: 225 : Token::simpleMatch(endOfCondition, ") {") ? endOfCondition->next() : NULL;
1227 [ - + ]: 225 : if (!startOfIfBlock)
1228 : 0 : continue;
1229 : :
1230 : : // If this if() statement may return, it may be a null
1231 : : // pointer check for the pointers referenced in its condition
1232 : 225 : const Token *endOfIf = startOfIfBlock->link();
1233 : : bool isExitOrReturn =
1234 [ + - ]: 225 : Token::findmatch(startOfIfBlock, "exit|return", endOfIf) != NULL;
1235 : :
1236 [ + + ]: 945 : for (const Token *tok2 = tok->next(); tok2 != endOfCondition; tok2 = tok2->next()) {
1237 [ + + ][ + + ]: 900 : if (tok2->isName() && tok2->varId() > 0 &&
[ + - ][ + + ]
1238 [ + - ]: 180 : pointerArgs.count(tok2->varId()) > 0) {
1239 : :
1240 : : // If the if() depends on a pointer and may return, stop
1241 : : // considering that pointer because it may be a NULL-pointer
1242 : : // check that returns if the pointer is NULL.
1243 [ + + ]: 180 : if (isExitOrReturn)
1244 [ + - ]: 45 : pointerArgs.erase(tok2->varId());
1245 : : else
1246 : 135 : dependsOnPointer = true;
1247 : : }
1248 : : }
1249 [ + + ][ + - ]: 225 : if (dependsOnPointer && endOfIf) {
1250 [ + + ]: 1710 : for (; tok != endOfIf; tok = tok->next()) {
1251 : : // If a pointer is assigned a new value, stop considering it.
1252 [ + - ][ + + ]: 1575 : if (Token::Match(tok, "%var% ="))
1253 [ + - ]: 135 : pointerArgs.erase(tok->varId());
1254 : : }
1255 : 135 : continue;
1256 : : }
1257 : : }
1258 : :
1259 [ + + ][ + - ]: 6390 : if (tok->varId() == 0 || pointerArgs.count(tok->varId()) == 0)
[ + + ][ + + ]
1260 : 5670 : continue;
1261 : :
1262 : : // If a pointer is assigned a new value, stop considering it.
1263 [ + - ][ + + ]: 720 : if (Token::Match(tok, "%var% ="))
1264 [ + - ]: 225 : pointerArgs.erase(tok->varId());
1265 : :
1266 : : // If a pointer dereference is preceded by an && or ||,
1267 : : // they serve as a sequence point so the dereference
1268 : : // may not be executed.
1269 [ + - ][ + + ]: 1980 : if (isPointerDeRef(tok, unknown) &&
[ + + ][ + - ]
[ + + ][ + + ]
[ + + ]
1270 [ + - ][ + - ]: 675 : tok->strAt(-1) != "&&" && tok->strAt(-1) != "||" &&
[ + - ][ + - ]
1271 [ + - ][ + - ]: 585 : tok->strAt(-2) != "&&" && tok->strAt(-2) != "||")
[ + - ][ + - ]
1272 [ + - ]: 225 : nullPointerDefaultArgError(tok, tok->str());
1273 : : }
1274 : : }
1275 : 12661 : }
1276 : 12391 : }
1277 : :
1278 : : /// @addtogroup Checks
1279 : : /// @{
1280 : :
1281 : :
1282 : : /**
1283 : : * @brief %Check for null pointer usage (using ExecutionPath)
1284 : : */
1285 : :
1286 [ + - ][ - + ]: 144337 : class Nullpointer : public ExecutionPath {
[ + - ]
1287 : : public:
1288 : : /** Startup constructor */
1289 [ + - ]: 12391 : Nullpointer(Check *c, const SymbolDatabase* symbolDatabase_) : ExecutionPath(c, 0), symbolDatabase(symbolDatabase_), null(false) {
1290 : 12391 : }
1291 : :
1292 : : private:
1293 : : const SymbolDatabase* symbolDatabase;
1294 : :
1295 : : /** Create checking of specific variable: */
1296 : 4851 : Nullpointer(Check *c, const unsigned int id, const std::string &name, const SymbolDatabase* symbolDatabase_)
1297 : : : ExecutionPath(c, id),
1298 : : symbolDatabase(symbolDatabase_),
1299 : : varname(name),
1300 [ + - ]: 4851 : null(false) {
1301 : 4851 : }
1302 : :
1303 : : /** Copy this check */
1304 : 40748 : ExecutionPath *copy() {
1305 [ + - ]: 40748 : return new Nullpointer(*this);
1306 : : }
1307 : :
1308 : : /** no implementation => compiler error if used by accident */
1309 : : void operator=(const Nullpointer &);
1310 : :
1311 : : /** is other execution path equal? */
1312 : 135 : bool is_equal(const ExecutionPath *e) const {
1313 : 135 : const Nullpointer *c = static_cast<const Nullpointer *>(e);
1314 [ + - ][ + + ]: 135 : return (varname == c->varname && null == c->null);
1315 : : }
1316 : :
1317 : : /** variable name for this check (empty => dummy check) */
1318 : : const std::string varname;
1319 : :
1320 : : /** is this variable null? */
1321 : : bool null;
1322 : :
1323 : : /** variable is set to null */
1324 : 2925 : static void setnull(std::list<ExecutionPath *> &checks, const unsigned int varid) {
1325 : 2925 : std::list<ExecutionPath *>::iterator it;
1326 [ + + ]: 8505 : for (it = checks.begin(); it != checks.end(); ++it) {
1327 [ - + ]: 5580 : Nullpointer *c = dynamic_cast<Nullpointer *>(*it);
1328 [ + - ][ + + ]: 5580 : if (c && c->varId == varid)
1329 : 2520 : c->null = true;
1330 : : }
1331 : 2925 : }
1332 : :
1333 : : /**
1334 : : * Dereferencing variable. Check if it is safe (if the variable is null there's an error)
1335 : : * @param checks Checks
1336 : : * @param tok token where dereferencing happens
1337 : : */
1338 : 12195 : static void dereference(std::list<ExecutionPath *> &checks, const Token *tok) {
1339 : 12195 : const unsigned int varid(tok->varId());
1340 : :
1341 : 12195 : std::list<ExecutionPath *>::iterator it;
1342 [ + + ]: 27000 : for (it = checks.begin(); it != checks.end(); ++it) {
1343 [ - + ]: 14805 : Nullpointer *c = dynamic_cast<Nullpointer *>(*it);
1344 [ + - ][ + + ]: 14805 : if (c && c->varId == varid && c->null) {
[ + + ]
1345 [ + - ][ + + ]: 7560 : for (const Token *tok2 = tok; tok2 && tok2->str() != ";"; tok2 = tok2->previous()) {
[ + + ]
1346 : : // Checking that pointer is not NULL
1347 [ + + ]: 6210 : if (Token::Match(tok2, "return|=|[|(|,|&& %varid% )| &&", varid))
1348 : 45 : return;
1349 [ + + ]: 6165 : if (Token::Match(tok2, "return|=|[|(|,|%oror% ! %varid% )| %oror%", varid))
1350 : 45 : return;
1351 : : }
1352 : :
1353 [ - + ]: 1350 : CheckNullPointer *checkNullPointer = dynamic_cast<CheckNullPointer *>(c->owner);
1354 [ + - ]: 1350 : if (checkNullPointer) {
1355 : 1350 : checkNullPointer->nullPointerError(tok, c->varname);
1356 : 1350 : return;
1357 : : }
1358 : : }
1359 : : }
1360 : : }
1361 : :
1362 : : /** parse tokens */
1363 : 169612 : const Token *parse(const Token &tok, std::list<ExecutionPath *> &checks) const {
1364 [ + + ]: 169612 : if (tok.varId() != 0) {
1365 : : // Pointer declaration declaration?
1366 : 30842 : const Variable *var = tok.variable();
1367 [ + + ][ + + ]: 30842 : if (var && var->isPointer() && var->nameToken() == &tok)
[ + + ][ + + ]
1368 [ + - ]: 4851 : checks.push_back(new Nullpointer(owner, var->varId(), var->name(), symbolDatabase));
1369 : : }
1370 : :
1371 [ + + ]: 169612 : if (Token::simpleMatch(&tok, "try {")) {
1372 : : // Bail out all used variables
1373 : 90 : const Token* tok2 = &tok;
1374 : 90 : const Token* endtok = tok.linkAt(1);
1375 [ + - ][ + + ]: 270 : for (; tok2 && tok2 != endtok; tok2 = tok2->next()) {
[ + + ]
1376 [ - + ]: 180 : if (tok2->varId())
1377 : 0 : bailOutVar(checks,tok2->varId());
1378 : : }
1379 : 90 : return tok2;
1380 : : }
1381 : :
1382 [ + + ]: 169522 : if (Token::Match(&tok, "%var% (")) {
1383 [ + + ][ + + ]: 8496 : if (tok.str() == "sizeof" || tok.str() == "typeid")
[ + + ]
1384 : 405 : return tok.next()->link();
1385 : :
1386 : : // parse usage..
1387 : 8091 : std::list<const Token *> var;
1388 [ + - ]: 8091 : CheckNullPointer::parseFunctionCall(tok, var, 0);
1389 [ + - ][ + - ]: 9936 : for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it)
[ + + ]
1390 [ + - ]: 9936 : dereference(checks, *it);
1391 : : }
1392 : :
1393 [ - + ]: 161026 : else if (Token::simpleMatch(&tok, "( 0 &&"))
1394 : 0 : return tok.link();
1395 : :
1396 [ + + ]: 169117 : if (tok.varId() != 0) {
1397 : : // unknown: if isPointerDeRef fails to determine if there
1398 : : // is a dereference this will be set to true.
1399 : 30842 : bool unknown = owner->inconclusiveFlag();
1400 : 30842 : bool deref = CheckNullPointer::isPointerDeRef(&tok, unknown);
1401 : :
1402 [ + + ]: 30842 : if (deref)
1403 : 6750 : dereference(checks, &tok);
1404 [ + + ][ + + ]: 24092 : else if (unknown && owner->inconclusiveFlag())
[ + + ]
1405 : 2565 : dereference(checks, &tok);
1406 [ + + ]: 30842 : if (Token::Match(tok.previous(), "[;{}=] %var% = 0 ;"))
1407 : 2925 : setnull(checks, tok.varId());
1408 [ + + + + : 71466 : else if (!deref &&
+ + + + +
+ ][ + + ]
1409 : 28313 : (!tok.previous()->isOp() || tok.previous()->str() == "&") &&
1410 : 15236 : (!tok.next()->isConstOp() || tok.next()->str() == ">>"))
1411 : 13706 : bailOutVar(checks, tok.varId()); // If its possible that the pointers value changes, bail out.
1412 : : }
1413 : :
1414 [ + + ]: 138275 : else if (tok.str() == "delete") {
1415 : 135 : const Token *ret = tok.next();
1416 [ + + ]: 135 : if (Token::simpleMatch(ret, "[ ]"))
1417 : 45 : ret = ret->tokAt(2);
1418 [ + - ]: 135 : if (Token::Match(ret, "%var% ;"))
1419 : 135 : return ret->next();
1420 : : }
1421 : :
1422 [ + + ]: 138140 : else if (tok.str() == "return") {
1423 : 2055 : bool unknown = owner->inconclusiveFlag();
1424 : 2055 : const Token* tok2 = &tok;
1425 [ + - ][ + + ]: 8370 : for (; tok2 && tok2->str() != ";"; tok2 = tok2->next()) {
[ + + ]
1426 [ + + ]: 6450 : if (tok2->varId()) {
1427 [ + + ][ - + ]: 1125 : if (CheckNullPointer::isPointerDeRef(tok2, unknown) || unknown)
[ + + ]
1428 : 540 : dereference(checks, tok2);
1429 : : }
1430 : :
1431 : : // If return statement contains "?" then assume there
1432 : : // is no dangours dereferencing later
1433 [ + + ]: 6450 : if (tok2->str() == "?") {
1434 [ + - ][ + + ]: 1170 : while (tok2 && tok2->str() != ";")
[ + + ]
1435 : 1035 : tok2 = tok2->next();
1436 : 135 : return tok2;
1437 : : }
1438 : : }
1439 : : }
1440 : :
1441 : 169612 : return &tok;
1442 : : }
1443 : :
1444 : : /** parse condition. @sa ExecutionPath::parseCondition */
1445 : 8145 : bool parseCondition(const Token &tok, std::list<ExecutionPath *> &checks) {
1446 [ + - ]: 21465 : for (const Token *tok2 = &tok; tok2; tok2 = tok2->next()) {
1447 [ + + ][ + + ]: 21465 : if (tok2->str() == "(" || tok2->str() == ")" || tok2->str() == "&&" || tok2->str() == "||" || tok2->str() == "?")
[ + + ][ + + ]
[ + + ][ + + ]
1448 : 8145 : break;
1449 : 13320 : bool unknown = owner->inconclusiveFlag();
1450 [ + + ][ + + ]: 13320 : if (tok2->varId() && (CheckNullPointer::isPointerDeRef(tok2, unknown) || unknown))
[ + + ][ + + ]
1451 : 405 : dereference(checks, tok2);
1452 : : }
1453 : :
1454 [ + + ]: 8145 : if (Token::Match(&tok, "!| %var% (")) {
1455 : 90 : std::list<const Token *> var;
1456 [ + - ][ + + ]: 90 : CheckNullPointer::parseFunctionCall(tok.str() == "!" ? *tok.next() : tok, var, 0);
[ + - ]
1457 [ + - ][ + - ]: 180 : for (std::list<const Token *>::const_iterator it = var.begin(); it != var.end(); ++it)
[ + + ]
1458 [ + - ]: 180 : dereference(checks, *it);
1459 : : }
1460 : :
1461 : 8145 : return ExecutionPath::parseCondition(tok, checks);
1462 : : }
1463 : :
1464 : :
1465 : 1170 : void parseLoopBody(const Token *tok, std::list<ExecutionPath *> &checks) const {
1466 [ + - ]: 8190 : while (tok) {
1467 [ + + ]: 8190 : if (Token::Match(tok, "{|}|return|goto|break|if"))
1468 : 1170 : return;
1469 : 7020 : const Token *next = parse(*tok, checks);
1470 [ + - ]: 7020 : if (next)
1471 : 7020 : tok = tok->next();
1472 : : }
1473 : : }
1474 : :
1475 : : };
1476 : : /// @}
1477 : :
1478 : :
1479 : 12391 : void CheckNullPointer::executionPaths()
1480 : : {
1481 : : // Check for null pointer errors..
1482 : 12391 : Nullpointer c(this, _tokenizer->getSymbolDatabase());
1483 [ + - ]: 12391 : checkExecutionPaths(_tokenizer->getSymbolDatabase(), &c);
1484 : 12391 : }
1485 : :
1486 : 1485 : void CheckNullPointer::nullPointerError(const Token *tok)
1487 : : {
1488 [ + - ][ + - ]: 1485 : reportError(tok, Severity::error, "nullPointer", "Null pointer dereference");
[ + - ][ + - ]
[ + - ]
1489 : 1485 : }
1490 : :
1491 : 1395 : void CheckNullPointer::nullPointerError(const Token *tok, const std::string &varname)
1492 : : {
1493 [ + - ][ + - ]: 1395 : reportError(tok, Severity::error, "nullPointer", "Possible null pointer dereference: " + varname);
[ + - ]
1494 : 1395 : }
1495 : :
1496 : 2565 : void CheckNullPointer::nullPointerError(const Token *tok, const std::string &varname, const Token* nullCheck, bool inconclusive)
1497 : : {
1498 : 2565 : std::list<const Token*> callstack;
1499 [ + - ]: 2565 : callstack.push_back(tok);
1500 [ + - ]: 2565 : callstack.push_back(nullCheck);
1501 [ + - ][ + - ]: 2565 : const std::string errmsg("Possible null pointer dereference: " + varname + " - otherwise it is redundant to check it against null.");
[ + - ]
1502 [ + - ][ + - ]: 2565 : reportError(callstack, Severity::error, "nullPointer", errmsg, inconclusive);
[ + - ][ + - ]
1503 : 2565 : }
1504 : :
1505 : 225 : void CheckNullPointer::nullPointerDefaultArgError(const Token *tok, const std::string &varname)
1506 : : {
1507 [ + - ][ + - ]: 225 : reportError(tok, Severity::warning, "nullPointer", "Possible null pointer dereference if the default parameter value is used: " + varname);
[ + - ]
1508 [ + - ][ + - ]: 360 : }
|