1 /*
2 * Cppcheck - A tool for static C/C++ code analysis
3 * Copyright (C) 2007-2021 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 "checktype.h"
22
23 #include "mathlib.h"
24 #include "platform.h"
25 #include "settings.h"
26 #include "symboldatabase.h"
27 #include "token.h"
28 #include "tokenize.h"
29
30 #include <cmath>
31 #include <list>
32 //---------------------------------------------------------------------------
33
34 // Register this check class (by creating a static instance of it)
35 namespace {
36 CheckType instance;
37 }
38
39 //---------------------------------------------------------------------------
40 // Checking for shift by too many bits
41 //---------------------------------------------------------------------------
42 //
43
44 // CWE ids used:
45 static const struct CWE CWE195(195U); // Signed to Unsigned Conversion Error
46 static const struct CWE CWE197(197U); // Numeric Truncation Error
47 static const struct CWE CWE758(758U); // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior
48 static const struct CWE CWE190(190U); // Integer Overflow or Wraparound
49
50
checkTooBigBitwiseShift()51 void CheckType::checkTooBigBitwiseShift()
52 {
53 // unknown sizeof(int) => can't run this checker
54 if (mSettings->platformType == Settings::Unspecified)
55 return;
56
57 for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
58 // C++ and macro: OUT(x<<y)
59 if (mTokenizer->isCPP() && Token::Match(tok, "[;{}] %name% (") && Token::simpleMatch(tok->linkAt(2), ") ;") && tok->next()->isUpperCaseName() && !tok->next()->function())
60 tok = tok->linkAt(2);
61
62 if (!tok->astOperand1() || !tok->astOperand2())
63 continue;
64
65 if (!Token::Match(tok, "<<|>>|<<=|>>="))
66 continue;
67
68 // get number of bits of lhs
69 const ValueType * const lhstype = tok->astOperand1()->valueType();
70 if (!lhstype || !lhstype->isIntegral() || lhstype->pointer >= 1)
71 continue;
72 // C11 Standard, section 6.5.7 Bitwise shift operators, states:
73 // The integer promotions are performed on each of the operands.
74 // The type of the result is that of the promoted left operand.
75 int lhsbits;
76 if ((lhstype->type == ValueType::Type::CHAR) ||
77 (lhstype->type == ValueType::Type::SHORT) ||
78 (lhstype->type == ValueType::Type::WCHAR_T) ||
79 (lhstype->type == ValueType::Type::BOOL) ||
80 (lhstype->type == ValueType::Type::INT))
81 lhsbits = mSettings->int_bit;
82 else if (lhstype->type == ValueType::Type::LONG)
83 lhsbits = mSettings->long_bit;
84 else if (lhstype->type == ValueType::Type::LONGLONG)
85 lhsbits = mSettings->long_long_bit;
86 else
87 continue;
88
89 // Get biggest rhs value. preferably a value which doesn't have 'condition'.
90 const ValueFlow::Value * value = tok->astOperand2()->getValueGE(lhsbits, mSettings);
91 if (value && mSettings->isEnabled(value, false))
92 tooBigBitwiseShiftError(tok, lhsbits, *value);
93 else if (lhstype->sign == ValueType::Sign::SIGNED) {
94 value = tok->astOperand2()->getValueGE(lhsbits-1, mSettings);
95 if (value && mSettings->isEnabled(value, false))
96 tooBigSignedBitwiseShiftError(tok, lhsbits, *value);
97 }
98 }
99 }
100
tooBigBitwiseShiftError(const Token * tok,int lhsbits,const ValueFlow::Value & rhsbits)101 void CheckType::tooBigBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits)
102 {
103 const char id[] = "shiftTooManyBits";
104
105 if (!tok) {
106 reportError(tok, Severity::error, id, "Shifting 32-bit value by 40 bits is undefined behaviour", CWE758, Certainty::normal);
107 return;
108 }
109
110 const ErrorPath errorPath = getErrorPath(tok, &rhsbits, "Shift");
111
112 std::ostringstream errmsg;
113 errmsg << "Shifting " << lhsbits << "-bit value by " << rhsbits.intvalue << " bits is undefined behaviour";
114 if (rhsbits.condition)
115 errmsg << ". See condition at line " << rhsbits.condition->linenr() << ".";
116
117 reportError(errorPath, rhsbits.errorSeverity() ? Severity::error : Severity::warning, id, errmsg.str(), CWE758, rhsbits.isInconclusive() ? Certainty::inconclusive : Certainty::normal);
118 }
119
tooBigSignedBitwiseShiftError(const Token * tok,int lhsbits,const ValueFlow::Value & rhsbits)120 void CheckType::tooBigSignedBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits)
121 {
122 const char id[] = "shiftTooManyBitsSigned";
123
124 const bool cpp14 = mSettings->standards.cpp >= Standards::CPP14;
125
126 std::string behaviour = "undefined";
127 if (cpp14)
128 behaviour = "implementation-defined";
129 if (!tok) {
130 reportError(tok, Severity::error, id, "Shifting signed 32-bit value by 31 bits is " + behaviour + " behaviour", CWE758, Certainty::normal);
131 return;
132 }
133
134 const ErrorPath errorPath = getErrorPath(tok, &rhsbits, "Shift");
135
136 std::ostringstream errmsg;
137 errmsg << "Shifting signed " << lhsbits << "-bit value by " << rhsbits.intvalue << " bits is " + behaviour + " behaviour";
138 if (rhsbits.condition)
139 errmsg << ". See condition at line " << rhsbits.condition->linenr() << ".";
140
141 Severity::SeverityType severity = rhsbits.errorSeverity() ? Severity::error : Severity::warning;
142 if (cpp14)
143 severity = Severity::portability;
144
145 if ((severity == Severity::portability) && !mSettings->severity.isEnabled(Severity::portability))
146 return;
147 reportError(errorPath, severity, id, errmsg.str(), CWE758, rhsbits.isInconclusive() ? Certainty::inconclusive : Certainty::normal);
148 }
149
150 //---------------------------------------------------------------------------
151 // Checking for integer overflow
152 //---------------------------------------------------------------------------
153
checkIntegerOverflow()154 void CheckType::checkIntegerOverflow()
155 {
156 // unknown sizeof(int) => can't run this checker
157 if (mSettings->platformType == Settings::Unspecified || mSettings->int_bit >= MathLib::bigint_bits)
158 return;
159
160 for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
161 if (!tok->isArithmeticalOp())
162 continue;
163
164 // is result signed integer?
165 const ValueType *vt = tok->valueType();
166 if (!vt || !vt->isIntegral() || vt->sign != ValueType::Sign::SIGNED)
167 continue;
168
169 unsigned int bits;
170 if (vt->type == ValueType::Type::INT)
171 bits = mSettings->int_bit;
172 else if (vt->type == ValueType::Type::LONG)
173 bits = mSettings->long_bit;
174 else if (vt->type == ValueType::Type::LONGLONG)
175 bits = mSettings->long_long_bit;
176 else
177 continue;
178
179 if (bits >= MathLib::bigint_bits)
180 continue;
181
182 // max value according to platform settings.
183 const MathLib::bigint maxvalue = (((MathLib::biguint)1) << (bits - 1)) - 1;
184
185 // is there a overflow result value
186 const ValueFlow::Value *value = tok->getValueGE(maxvalue + 1, mSettings);
187 if (!value)
188 value = tok->getValueLE(-maxvalue - 2, mSettings);
189 if (!value || !mSettings->isEnabled(value,false))
190 continue;
191
192 // For left shift, it's common practice to shift into the sign bit
193 //if (tok->str() == "<<" && value->intvalue > 0 && value->intvalue < (((MathLib::bigint)1) << bits))
194 // continue;
195
196 integerOverflowError(tok, *value);
197 }
198 }
199
integerOverflowError(const Token * tok,const ValueFlow::Value & value)200 void CheckType::integerOverflowError(const Token *tok, const ValueFlow::Value &value)
201 {
202 const std::string expr(tok ? tok->expressionString() : "");
203
204 std::string msg;
205 if (value.condition)
206 msg = ValueFlow::eitherTheConditionIsRedundant(value.condition) +
207 " or there is signed integer overflow for expression '" + expr + "'.";
208 else
209 msg = "Signed integer overflow for expression '" + expr + "'.";
210
211 if (value.safe)
212 msg = "Safe checks: " + msg;
213
214 reportError(getErrorPath(tok, &value, "Integer overflow"),
215 value.errorSeverity() ? Severity::error : Severity::warning,
216 getMessageId(value, "integerOverflow").c_str(),
217 msg,
218 CWE190,
219 value.isInconclusive() ? Certainty::inconclusive : Certainty::normal);
220 }
221
222 //---------------------------------------------------------------------------
223 // Checking for sign conversion when operand can be negative
224 //---------------------------------------------------------------------------
225
checkSignConversion()226 void CheckType::checkSignConversion()
227 {
228 if (!mSettings->severity.isEnabled(Severity::warning))
229 return;
230
231 for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
232 if (!tok->isArithmeticalOp() || Token::Match(tok,"+|-"))
233 continue;
234
235 // Is result unsigned?
236 if (!(tok->valueType() && tok->valueType()->sign == ValueType::Sign::UNSIGNED))
237 continue;
238
239 // Check if an operand can be negative..
240 const Token * astOperands[] = { tok->astOperand1(), tok->astOperand2() };
241 for (const Token * tok1 : astOperands) {
242 if (!tok1)
243 continue;
244 const ValueFlow::Value* negativeValue =
245 ValueFlow::findValue(tok1->values(), mSettings, [&](const ValueFlow::Value& v) {
246 return !v.isImpossible() && v.isIntValue() && (v.intvalue <= -1 || v.wideintvalue <= -1);
247 });
248 if (!negativeValue)
249 continue;
250 if (tok1->valueType() && tok1->valueType()->sign != ValueType::Sign::UNSIGNED)
251 signConversionError(tok1, negativeValue, tok1->isNumber());
252 }
253 }
254 }
255
signConversionError(const Token * tok,const ValueFlow::Value * negativeValue,const bool constvalue)256 void CheckType::signConversionError(const Token *tok, const ValueFlow::Value *negativeValue, const bool constvalue)
257 {
258 const std::string expr(tok ? tok->expressionString() : "var");
259
260 std::ostringstream msg;
261 if (tok && tok->isName())
262 msg << "$symbol:" << expr << "\n";
263 if (constvalue)
264 msg << "Expression '" << expr << "' has a negative value. That is converted to an unsigned value and used in an unsigned calculation.";
265 else
266 msg << "Expression '" << expr << "' can have a negative value. That is converted to an unsigned value and used in an unsigned calculation.";
267
268 if (!negativeValue)
269 reportError(tok, Severity::warning, "signConversion", msg.str(), CWE195, Certainty::normal);
270 else {
271 const ErrorPath &errorPath = getErrorPath(tok,negativeValue,"Negative value is converted to an unsigned value");
272 reportError(errorPath,
273 Severity::warning,
274 Check::getMessageId(*negativeValue, "signConversion").c_str(),
275 msg.str(),
276 CWE195,
277 negativeValue->isInconclusive() ? Certainty::inconclusive : Certainty::normal);
278 }
279 }
280
281
282 //---------------------------------------------------------------------------
283 // Checking for long cast of int result const long x = var1 * var2;
284 //---------------------------------------------------------------------------
285
checkLongCast()286 void CheckType::checkLongCast()
287 {
288 if (!mSettings->severity.isEnabled(Severity::style))
289 return;
290
291 // Assignments..
292 for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
293 if (tok->str() != "=" || !Token::Match(tok->astOperand2(), "*|<<"))
294 continue;
295
296 if (tok->astOperand2()->hasKnownIntValue()) {
297 const ValueFlow::Value &v = tok->astOperand2()->values().front();
298 if (mSettings->isIntValue(v.intvalue))
299 continue;
300 }
301
302 const ValueType *lhstype = tok->astOperand1() ? tok->astOperand1()->valueType() : nullptr;
303 const ValueType *rhstype = tok->astOperand2()->valueType();
304
305 if (!lhstype || !rhstype)
306 continue;
307
308 // assign int result to long/longlong const nonpointer?
309 if (rhstype->type == ValueType::Type::INT &&
310 rhstype->pointer == 0U &&
311 rhstype->originalTypeName.empty() &&
312 (lhstype->type == ValueType::Type::LONG || lhstype->type == ValueType::Type::LONGLONG) &&
313 lhstype->pointer == 0U &&
314 lhstype->constness == 1U &&
315 lhstype->originalTypeName.empty())
316 longCastAssignError(tok);
317 }
318
319 // Return..
320 const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
321 for (const Scope * scope : symbolDatabase->functionScopes) {
322
323 // function must return long data
324 const Token * def = scope->classDef;
325 bool islong = false;
326 while (Token::Match(def, "%type%|::")) {
327 if (def->str() == "long" && def->originalName().empty()) {
328 islong = true;
329 break;
330 }
331 def = def->previous();
332 }
333 if (!islong)
334 continue;
335
336 // return statements
337 const Token *ret = nullptr;
338 for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
339 if (tok->str() == "return") {
340 if (Token::Match(tok->astOperand1(), "<<|*")) {
341 const ValueType *type = tok->astOperand1()->valueType();
342 if (type && type->type == ValueType::Type::INT && type->pointer == 0U && type->originalTypeName.empty())
343 ret = tok;
344 }
345 // All return statements must have problem otherwise no warning
346 if (ret != tok) {
347 ret = nullptr;
348 break;
349 }
350 }
351 }
352
353 if (ret)
354 longCastReturnError(ret);
355 }
356 }
357
longCastAssignError(const Token * tok)358 void CheckType::longCastAssignError(const Token *tok)
359 {
360 reportError(tok,
361 Severity::style,
362 "truncLongCastAssignment",
363 "int result is assigned to long variable. If the variable is long to avoid loss of information, then you have loss of information.\n"
364 "int result is assigned to long variable. If the variable is long to avoid loss of information, then there is loss of information. To avoid loss of information you must cast a calculation operand to long, for example 'l = a * b;' => 'l = (long)a * b;'.", CWE197, Certainty::normal);
365 }
366
longCastReturnError(const Token * tok)367 void CheckType::longCastReturnError(const Token *tok)
368 {
369 reportError(tok,
370 Severity::style,
371 "truncLongCastReturn",
372 "int result is returned as long value. If the return value is long to avoid loss of information, then you have loss of information.\n"
373 "int result is returned as long value. If the return value is long to avoid loss of information, then there is loss of information. To avoid loss of information you must cast a calculation operand to long, for example 'return a*b;' => 'return (long)a*b'.", CWE197, Certainty::normal);
374 }
375
376 //---------------------------------------------------------------------------
377 // Checking for float to integer overflow
378 //---------------------------------------------------------------------------
379
checkFloatToIntegerOverflow()380 void CheckType::checkFloatToIntegerOverflow()
381 {
382 for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
383 const ValueType *vtint, *vtfloat;
384 const std::list<ValueFlow::Value> *floatValues;
385
386 // Explicit cast
387 if (Token::Match(tok, "( %name%") && tok->astOperand1() && !tok->astOperand2()) {
388 vtint = tok->valueType();
389 vtfloat = tok->astOperand1()->valueType();
390 floatValues = &tok->astOperand1()->values();
391 checkFloatToIntegerOverflow(tok, vtint, vtfloat, floatValues);
392 }
393
394 // Assignment
395 else if (tok->str() == "=" && tok->astOperand1() && tok->astOperand2()) {
396 vtint = tok->astOperand1()->valueType();
397 vtfloat = tok->astOperand2()->valueType();
398 floatValues = &tok->astOperand2()->values();
399 checkFloatToIntegerOverflow(tok, vtint, vtfloat, floatValues);
400 }
401
402 else if (tok->str() == "return" && tok->astOperand1() && tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->isFloat()) {
403 const Scope *scope = tok->scope();
404 while (scope && scope->type != Scope::ScopeType::eLambda && scope->type != Scope::ScopeType::eFunction)
405 scope = scope->nestedIn;
406 if (scope && scope->type == Scope::ScopeType::eFunction && scope->function && scope->function->retDef) {
407 const ValueType &valueType = ValueType::parseDecl(scope->function->retDef, mSettings);
408 vtfloat = tok->astOperand1()->valueType();
409 floatValues = &tok->astOperand1()->values();
410 checkFloatToIntegerOverflow(tok, &valueType, vtfloat, floatValues);
411 }
412 }
413 }
414 }
415
checkFloatToIntegerOverflow(const Token * tok,const ValueType * vtint,const ValueType * vtfloat,const std::list<ValueFlow::Value> * floatValues)416 void CheckType::checkFloatToIntegerOverflow(const Token *tok, const ValueType *vtint, const ValueType *vtfloat, const std::list<ValueFlow::Value> *floatValues)
417 {
418 // Conversion of float to integer?
419 if (!vtint || !vtint->isIntegral())
420 return;
421 if (!vtfloat || !vtfloat->isFloat())
422 return;
423
424 for (const ValueFlow::Value &f : *floatValues) {
425 if (f.valueType != ValueFlow::Value::ValueType::FLOAT)
426 continue;
427 if (!mSettings->isEnabled(&f, false))
428 continue;
429 if (f.floatValue >= std::exp2(mSettings->long_long_bit))
430 floatToIntegerOverflowError(tok, f);
431 else if ((-f.floatValue) > std::exp2(mSettings->long_long_bit - 1))
432 floatToIntegerOverflowError(tok, f);
433 else if (mSettings->platformType != Settings::Unspecified) {
434 int bits = 0;
435 if (vtint->type == ValueType::Type::CHAR)
436 bits = mSettings->char_bit;
437 else if (vtint->type == ValueType::Type::SHORT)
438 bits = mSettings->short_bit;
439 else if (vtint->type == ValueType::Type::INT)
440 bits = mSettings->int_bit;
441 else if (vtint->type == ValueType::Type::LONG)
442 bits = mSettings->long_bit;
443 else if (vtint->type == ValueType::Type::LONGLONG)
444 bits = mSettings->long_long_bit;
445 else
446 continue;
447 if (bits < MathLib::bigint_bits && f.floatValue >= (((MathLib::biguint)1) << bits))
448 floatToIntegerOverflowError(tok, f);
449 }
450 }
451 }
452
floatToIntegerOverflowError(const Token * tok,const ValueFlow::Value & value)453 void CheckType::floatToIntegerOverflowError(const Token *tok, const ValueFlow::Value &value)
454 {
455 std::ostringstream errmsg;
456 errmsg << "Undefined behaviour: float (" << value.floatValue << ") to integer conversion overflow.";
457 reportError(getErrorPath(tok, &value, "float to integer conversion"),
458 value.errorSeverity() ? Severity::error : Severity::warning,
459 "floatConversionOverflow",
460 errmsg.str(), CWE190, value.isInconclusive() ? Certainty::inconclusive : Certainty::normal);
461 }
462