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