2014-01-04 20:57:02 +01:00
|
|
|
/*
|
|
|
|
* Cppcheck - A tool for static C/C++ code analysis
|
2022-02-05 11:45:17 +01:00
|
|
|
* Copyright (C) 2007-2022 Cppcheck team.
|
2014-01-04 20:57:02 +01:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
#ifndef valueflowH
|
|
|
|
#define valueflowH
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2017-05-27 04:33:47 +02:00
|
|
|
#include "config.h"
|
2020-02-17 10:31:08 +01:00
|
|
|
#include "mathlib.h"
|
2017-05-27 04:33:47 +02:00
|
|
|
|
2022-01-27 19:03:20 +01:00
|
|
|
#include <algorithm>
|
2021-07-30 21:29:35 +02:00
|
|
|
#include <cassert>
|
2022-01-27 19:03:20 +01:00
|
|
|
#include <cstdlib>
|
2020-11-10 16:00:55 +01:00
|
|
|
#include <functional>
|
2017-05-15 20:05:11 +02:00
|
|
|
#include <list>
|
2015-07-29 19:54:57 +02:00
|
|
|
#include <string>
|
2020-11-10 16:00:55 +01:00
|
|
|
#include <type_traits>
|
2017-05-27 04:33:47 +02:00
|
|
|
#include <utility>
|
2019-09-11 19:25:09 +02:00
|
|
|
#include <vector>
|
2015-07-29 19:54:57 +02:00
|
|
|
|
2014-01-05 20:06:46 +01:00
|
|
|
class ErrorLogger;
|
2021-10-30 22:13:58 +02:00
|
|
|
struct InferModel;
|
2014-01-05 20:06:46 +01:00
|
|
|
class Settings;
|
2017-05-27 04:33:47 +02:00
|
|
|
class SymbolDatabase;
|
|
|
|
class Token;
|
|
|
|
class TokenList;
|
Set correct type and size of string and char literals (#2275)
* Set correct type and size of string and char literals
Use that string and char literal tokens store the prefix. This makes
it possible to distinghuish between different type of string literals
(i.e., utf8 encoded strings, utf16, wide strings, etc) which have
different type.
When the tokens holding the string and character values have the correct
type, it is possible to improve Token::getStrSize() to give the correct
result for all string types. Previously, it would return the number of
characters in the string, i.e., it would give the wrong size unless
the type of the string was char*.
Since strings now can have different size (in number of bytes) and
length (in number of elements), add a new helper function that returns
the number of characters. Checkers have been updated to use the correct
functions.
Having the size makes it possible to find more problems with prefixed
strings, and to reduce false positives, for example in the buffer
overflow checker.
Also, improve the stringLiteralWrite error message to also print the
prefix of the string (if there is one).
* Add comment and update string length
2019-10-20 07:11:57 +02:00
|
|
|
class ValueType;
|
2019-01-23 07:29:16 +01:00
|
|
|
class Variable;
|
2022-02-22 09:51:44 +01:00
|
|
|
class Scope;
|
2014-01-04 20:57:02 +01:00
|
|
|
|
2021-10-30 22:13:58 +02:00
|
|
|
template<class T>
|
|
|
|
class ValuePtr;
|
|
|
|
|
2014-01-04 20:57:02 +01:00
|
|
|
namespace ValueFlow {
|
2019-09-20 15:07:27 +02:00
|
|
|
struct increment {
|
2021-08-07 20:51:18 +02:00
|
|
|
template<class T>
|
2019-09-20 15:07:27 +02:00
|
|
|
void operator()(T& x) const {
|
|
|
|
x++;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
struct decrement {
|
2021-08-07 20:51:18 +02:00
|
|
|
template<class T>
|
2019-09-20 15:07:27 +02:00
|
|
|
void operator()(T& x) const {
|
|
|
|
x--;
|
|
|
|
}
|
|
|
|
};
|
2020-11-10 16:00:55 +01:00
|
|
|
|
2021-03-30 14:02:28 +02:00
|
|
|
struct less {
|
2021-08-07 20:51:18 +02:00
|
|
|
template<class T, class U>
|
2021-04-04 18:20:32 +02:00
|
|
|
bool operator()(const T& x, const U& y) const {
|
2021-03-30 14:02:28 +02:00
|
|
|
return x < y;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct adjacent {
|
2021-08-07 20:51:18 +02:00
|
|
|
template<class T, class U>
|
2021-04-04 18:20:32 +02:00
|
|
|
bool operator()(const T& x, const U& y) const {
|
2021-03-30 14:02:28 +02:00
|
|
|
return std::abs(x - y) == 1;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-10 16:00:55 +01:00
|
|
|
struct equalVisitor {
|
2021-08-07 20:51:18 +02:00
|
|
|
template<class T, class U>
|
2020-11-11 09:15:36 +01:00
|
|
|
void operator()(bool& result, T x, U y) const {
|
2020-11-10 16:00:55 +01:00
|
|
|
result = !(x > y || x < y);
|
|
|
|
}
|
|
|
|
};
|
2015-10-07 13:38:34 +02:00
|
|
|
class CPPCHECKLIB Value {
|
2014-01-07 19:20:56 +01:00
|
|
|
public:
|
2017-05-16 22:38:13 +02:00
|
|
|
typedef std::pair<const Token *, std::string> ErrorPathItem;
|
|
|
|
typedef std::list<ErrorPathItem> ErrorPath;
|
2021-08-16 09:19:07 +02:00
|
|
|
enum class Bound { Upper, Lower, Point };
|
2017-05-16 22:38:13 +02:00
|
|
|
|
2021-08-16 09:19:07 +02:00
|
|
|
explicit Value(long long val = 0, Bound b = Bound::Point)
|
2019-07-10 14:04:56 +02:00
|
|
|
: valueType(ValueType::INT),
|
2021-08-16 09:19:07 +02:00
|
|
|
bound(b),
|
2021-08-07 20:51:18 +02:00
|
|
|
intvalue(val),
|
|
|
|
tokvalue(nullptr),
|
|
|
|
floatValue(0.0),
|
|
|
|
moveKind(MoveKind::NonMovedVariable),
|
|
|
|
varvalue(val),
|
|
|
|
condition(nullptr),
|
|
|
|
varId(0U),
|
|
|
|
safe(false),
|
|
|
|
conditional(false),
|
2021-11-25 18:40:15 +01:00
|
|
|
macro(false),
|
2021-08-07 20:51:18 +02:00
|
|
|
defaultArg(false),
|
|
|
|
indirect(0),
|
|
|
|
path(0),
|
|
|
|
wideintvalue(val),
|
2021-10-30 07:43:37 +02:00
|
|
|
subexpressions(),
|
2022-04-30 09:36:28 +02:00
|
|
|
capturetok(nullptr),
|
2021-08-07 20:51:18 +02:00
|
|
|
lifetimeKind(LifetimeKind::Object),
|
|
|
|
lifetimeScope(LifetimeScope::Local),
|
|
|
|
valueKind(ValueKind::Possible)
|
2019-01-29 09:47:52 +01:00
|
|
|
{}
|
2021-08-16 09:19:07 +02:00
|
|
|
Value(const Token* c, long long val, Bound b = Bound::Point);
|
|
|
|
|
|
|
|
static Value unknown();
|
2014-01-18 19:30:44 +01:00
|
|
|
|
2019-09-05 15:15:58 +02:00
|
|
|
bool equalValue(const ValueFlow::Value& rhs) const {
|
2016-11-13 22:33:39 +01:00
|
|
|
if (valueType != rhs.valueType)
|
|
|
|
return false;
|
|
|
|
switch (valueType) {
|
2019-07-10 14:04:56 +02:00
|
|
|
case ValueType::INT:
|
2020-08-17 23:36:45 +02:00
|
|
|
case ValueType::CONTAINER_SIZE:
|
|
|
|
case ValueType::BUFFER_SIZE:
|
|
|
|
case ValueType::ITERATOR_START:
|
|
|
|
case ValueType::ITERATOR_END:
|
2016-11-13 22:33:39 +01:00
|
|
|
if (intvalue != rhs.intvalue)
|
|
|
|
return false;
|
|
|
|
break;
|
2019-07-10 14:04:56 +02:00
|
|
|
case ValueType::TOK:
|
2016-11-13 22:33:39 +01:00
|
|
|
if (tokvalue != rhs.tokvalue)
|
|
|
|
return false;
|
|
|
|
break;
|
2019-07-10 14:04:56 +02:00
|
|
|
case ValueType::FLOAT:
|
2016-11-13 22:59:56 +01:00
|
|
|
// TODO: Write some better comparison
|
|
|
|
if (floatValue > rhs.floatValue || floatValue < rhs.floatValue)
|
|
|
|
return false;
|
|
|
|
break;
|
2019-07-10 14:04:56 +02:00
|
|
|
case ValueType::MOVED:
|
2016-11-20 15:14:49 +01:00
|
|
|
if (moveKind != rhs.moveKind)
|
|
|
|
return false;
|
|
|
|
break;
|
2019-07-10 14:04:56 +02:00
|
|
|
case ValueType::UNINIT:
|
2017-04-23 18:05:14 +02:00
|
|
|
break;
|
2019-07-10 14:04:56 +02:00
|
|
|
case ValueType::LIFETIME:
|
2018-11-10 16:40:40 +01:00
|
|
|
if (tokvalue != rhs.tokvalue)
|
|
|
|
return false;
|
2021-07-30 21:29:35 +02:00
|
|
|
break;
|
|
|
|
case ValueType::SYMBOLIC:
|
2021-08-19 22:01:55 +02:00
|
|
|
if (!sameToken(tokvalue, rhs.tokvalue))
|
2021-07-30 21:29:35 +02:00
|
|
|
return false;
|
|
|
|
if (intvalue != rhs.intvalue)
|
|
|
|
return false;
|
|
|
|
break;
|
2019-06-30 21:43:25 +02:00
|
|
|
}
|
2019-09-05 15:15:58 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-08-07 20:51:18 +02:00
|
|
|
template<class T, class F>
|
2020-11-11 09:15:36 +01:00
|
|
|
static void visitValue(T& self, F f) {
|
2020-11-10 16:00:55 +01:00
|
|
|
switch (self.valueType) {
|
2019-09-20 15:06:37 +02:00
|
|
|
case ValueType::INT:
|
2021-07-30 21:29:35 +02:00
|
|
|
case ValueType::SYMBOLIC:
|
2019-09-20 15:06:37 +02:00
|
|
|
case ValueType::BUFFER_SIZE:
|
2020-08-17 23:36:45 +02:00
|
|
|
case ValueType::CONTAINER_SIZE:
|
|
|
|
case ValueType::ITERATOR_START:
|
|
|
|
case ValueType::ITERATOR_END: {
|
2020-11-10 16:00:55 +01:00
|
|
|
f(self.intvalue);
|
2019-09-20 15:06:37 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ValueType::FLOAT: {
|
2020-11-10 16:00:55 +01:00
|
|
|
f(self.floatValue);
|
2019-09-20 15:06:37 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ValueType::UNINIT:
|
|
|
|
case ValueType::TOK:
|
|
|
|
case ValueType::LIFETIME:
|
|
|
|
case ValueType::MOVED:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-30 14:02:28 +02:00
|
|
|
struct compareVisitor {
|
|
|
|
struct innerVisitor {
|
2021-08-07 20:51:18 +02:00
|
|
|
template<class Compare, class T, class U>
|
2021-04-04 18:20:32 +02:00
|
|
|
void operator()(bool& result, Compare compare, T x, U y) const {
|
2021-03-30 14:02:28 +02:00
|
|
|
result = compare(x, y);
|
|
|
|
}
|
|
|
|
};
|
2021-08-07 20:51:18 +02:00
|
|
|
template<class Compare, class T>
|
2021-04-04 18:20:32 +02:00
|
|
|
void operator()(bool& result, const Value& rhs, Compare compare, T x) const {
|
2021-03-30 14:02:28 +02:00
|
|
|
visitValue(rhs,
|
|
|
|
std::bind(innerVisitor{}, std::ref(result), std::move(compare), x, std::placeholders::_1));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-08-07 20:51:18 +02:00
|
|
|
template<class Compare>
|
2021-04-04 18:20:32 +02:00
|
|
|
bool compareValue(const Value& rhs, Compare compare) const {
|
2021-07-30 21:29:35 +02:00
|
|
|
assert((!this->isSymbolicValue() && !rhs.isSymbolicValue()) ||
|
2021-08-19 22:01:55 +02:00
|
|
|
(this->valueType == rhs.valueType && sameToken(this->tokvalue, rhs.tokvalue)));
|
2021-03-30 14:02:28 +02:00
|
|
|
bool result = false;
|
|
|
|
visitValue(
|
|
|
|
*this,
|
|
|
|
std::bind(compareVisitor{}, std::ref(result), std::ref(rhs), std::move(compare), std::placeholders::_1));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-09-05 15:15:58 +02:00
|
|
|
bool operator==(const Value &rhs) const {
|
|
|
|
if (!equalValue(rhs))
|
|
|
|
return false;
|
2016-11-13 22:33:39 +01:00
|
|
|
|
|
|
|
return varvalue == rhs.varvalue &&
|
2016-08-15 14:19:35 +02:00
|
|
|
condition == rhs.condition &&
|
|
|
|
varId == rhs.varId &&
|
|
|
|
conditional == rhs.conditional &&
|
|
|
|
defaultArg == rhs.defaultArg &&
|
2019-08-17 07:36:41 +02:00
|
|
|
indirect == rhs.indirect &&
|
2016-08-15 14:19:35 +02:00
|
|
|
valueKind == rhs.valueKind;
|
|
|
|
}
|
|
|
|
|
2019-09-05 15:15:58 +02:00
|
|
|
bool operator!=(const Value &rhs) const {
|
|
|
|
return !(*this == rhs);
|
|
|
|
}
|
|
|
|
|
2021-08-07 20:51:18 +02:00
|
|
|
template<class T, REQUIRES("T must be an arithmetic type", std::is_arithmetic<T> )>
|
2020-11-11 09:15:36 +01:00
|
|
|
bool equalTo(const T& x) const {
|
2020-11-10 16:00:55 +01:00
|
|
|
bool result = false;
|
|
|
|
visitValue(*this, std::bind(equalVisitor{}, std::ref(result), x, std::placeholders::_1));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-09-20 15:07:27 +02:00
|
|
|
void decreaseRange() {
|
2019-09-20 15:06:37 +02:00
|
|
|
if (bound == Bound::Lower)
|
2020-11-10 16:00:55 +01:00
|
|
|
visitValue(*this, increment{});
|
2019-09-20 15:06:37 +02:00
|
|
|
else if (bound == Bound::Upper)
|
2020-11-10 16:00:55 +01:00
|
|
|
visitValue(*this, decrement{});
|
2019-09-20 15:06:37 +02:00
|
|
|
}
|
|
|
|
|
2019-12-26 15:47:53 +01:00
|
|
|
void invertBound() {
|
2019-09-20 15:06:37 +02:00
|
|
|
if (bound == Bound::Lower)
|
|
|
|
bound = Bound::Upper;
|
|
|
|
else if (bound == Bound::Upper)
|
|
|
|
bound = Bound::Lower;
|
2019-12-26 15:47:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void invertRange() {
|
|
|
|
invertBound();
|
2019-09-20 15:06:37 +02:00
|
|
|
decreaseRange();
|
|
|
|
}
|
|
|
|
|
2020-08-28 19:29:09 +02:00
|
|
|
void assumeCondition(const Token* tok);
|
|
|
|
|
2017-05-19 16:32:58 +02:00
|
|
|
std::string infoString() const;
|
|
|
|
|
2021-07-30 21:29:35 +02:00
|
|
|
enum class ValueType {
|
|
|
|
INT,
|
|
|
|
TOK,
|
|
|
|
FLOAT,
|
|
|
|
MOVED,
|
|
|
|
UNINIT,
|
|
|
|
CONTAINER_SIZE,
|
|
|
|
LIFETIME,
|
|
|
|
BUFFER_SIZE,
|
|
|
|
ITERATOR_START,
|
|
|
|
ITERATOR_END,
|
|
|
|
SYMBOLIC
|
|
|
|
} valueType;
|
2016-11-13 22:33:39 +01:00
|
|
|
bool isIntValue() const {
|
2019-07-10 14:04:56 +02:00
|
|
|
return valueType == ValueType::INT;
|
2016-11-13 22:33:39 +01:00
|
|
|
}
|
|
|
|
bool isTokValue() const {
|
2019-07-10 14:04:56 +02:00
|
|
|
return valueType == ValueType::TOK;
|
2016-11-13 22:33:39 +01:00
|
|
|
}
|
2016-11-13 22:59:56 +01:00
|
|
|
bool isFloatValue() const {
|
2019-07-10 14:04:56 +02:00
|
|
|
return valueType == ValueType::FLOAT;
|
2016-11-13 22:59:56 +01:00
|
|
|
}
|
2016-11-20 15:14:49 +01:00
|
|
|
bool isMovedValue() const {
|
2019-07-10 14:04:56 +02:00
|
|
|
return valueType == ValueType::MOVED;
|
2016-11-20 15:14:49 +01:00
|
|
|
}
|
2017-04-23 18:05:14 +02:00
|
|
|
bool isUninitValue() const {
|
2019-07-10 14:04:56 +02:00
|
|
|
return valueType == ValueType::UNINIT;
|
2017-04-23 18:05:14 +02:00
|
|
|
}
|
2018-08-10 11:29:16 +02:00
|
|
|
bool isContainerSizeValue() const {
|
2019-07-10 14:04:56 +02:00
|
|
|
return valueType == ValueType::CONTAINER_SIZE;
|
2018-08-10 11:29:16 +02:00
|
|
|
}
|
2018-11-10 16:40:40 +01:00
|
|
|
bool isLifetimeValue() const {
|
2019-07-10 14:04:56 +02:00
|
|
|
return valueType == ValueType::LIFETIME;
|
2018-11-10 16:40:40 +01:00
|
|
|
}
|
2019-03-17 13:09:15 +01:00
|
|
|
bool isBufferSizeValue() const {
|
2019-07-10 14:04:56 +02:00
|
|
|
return valueType == ValueType::BUFFER_SIZE;
|
2019-03-17 13:09:15 +01:00
|
|
|
}
|
2020-08-17 23:36:45 +02:00
|
|
|
bool isIteratorValue() const {
|
|
|
|
return valueType == ValueType::ITERATOR_START || valueType == ValueType::ITERATOR_END;
|
|
|
|
}
|
|
|
|
bool isIteratorStartValue() const {
|
|
|
|
return valueType == ValueType::ITERATOR_START;
|
|
|
|
}
|
|
|
|
bool isIteratorEndValue() const {
|
|
|
|
return valueType == ValueType::ITERATOR_END;
|
|
|
|
}
|
2021-08-01 14:05:30 +02:00
|
|
|
bool isSymbolicValue() const {
|
|
|
|
return valueType == ValueType::SYMBOLIC;
|
|
|
|
}
|
2016-11-13 22:33:39 +01:00
|
|
|
|
2019-01-29 09:48:18 +01:00
|
|
|
bool isLocalLifetimeValue() const {
|
2019-07-16 11:12:35 +02:00
|
|
|
return valueType == ValueType::LIFETIME && lifetimeScope == LifetimeScope::Local;
|
2019-01-29 09:48:18 +01:00
|
|
|
}
|
2019-01-29 09:47:52 +01:00
|
|
|
|
2019-01-29 09:48:18 +01:00
|
|
|
bool isArgumentLifetimeValue() const {
|
2019-07-16 11:12:35 +02:00
|
|
|
return valueType == ValueType::LIFETIME && lifetimeScope == LifetimeScope::Argument;
|
2019-01-29 09:48:18 +01:00
|
|
|
}
|
2019-01-29 09:47:52 +01:00
|
|
|
|
2020-09-10 08:02:45 +02:00
|
|
|
bool isSubFunctionLifetimeValue() const {
|
2020-09-04 18:56:34 +02:00
|
|
|
return valueType == ValueType::LIFETIME && lifetimeScope == LifetimeScope::SubFunction;
|
|
|
|
}
|
|
|
|
|
2019-08-16 07:48:54 +02:00
|
|
|
bool isNonValue() const {
|
|
|
|
return isMovedValue() || isUninitValue() || isLifetimeValue();
|
|
|
|
}
|
|
|
|
|
2019-09-20 15:06:37 +02:00
|
|
|
/** The value bound */
|
2021-08-16 09:19:07 +02:00
|
|
|
Bound bound;
|
2019-09-20 15:06:37 +02:00
|
|
|
|
2021-02-23 08:19:05 +01:00
|
|
|
/** int value (or sometimes bool value?) */
|
2014-04-02 20:09:53 +02:00
|
|
|
long long intvalue;
|
2014-01-18 19:30:44 +01:00
|
|
|
|
2014-08-03 20:11:22 +02:00
|
|
|
/** token value - the token that has the value. this is used for pointer aliases, strings, etc. */
|
|
|
|
const Token *tokvalue;
|
|
|
|
|
2016-11-13 22:59:56 +01:00
|
|
|
/** float value */
|
|
|
|
double floatValue;
|
|
|
|
|
2016-11-20 15:14:49 +01:00
|
|
|
/** kind of moved */
|
2019-07-10 15:27:07 +02:00
|
|
|
enum class MoveKind {NonMovedVariable, MovedVariable, ForwardedVariable} moveKind;
|
2016-11-20 15:14:49 +01:00
|
|
|
|
2014-01-20 21:45:30 +01:00
|
|
|
/** For calculated values - variable value that calculated value depends on */
|
2014-04-02 20:09:53 +02:00
|
|
|
long long varvalue;
|
|
|
|
|
2017-05-16 22:38:13 +02:00
|
|
|
/** Condition that this value depends on */
|
2014-05-19 14:37:54 +02:00
|
|
|
const Token *condition;
|
|
|
|
|
2017-05-16 22:38:13 +02:00
|
|
|
ErrorPath errorPath;
|
2017-05-15 20:05:11 +02:00
|
|
|
|
2014-05-19 14:37:54 +02:00
|
|
|
/** For calculated values - varId that calculated value depends on */
|
2019-07-15 13:47:17 +02:00
|
|
|
nonneg int varId;
|
2014-05-19 14:37:54 +02:00
|
|
|
|
2019-07-25 17:19:51 +02:00
|
|
|
/** value relies on safe checking */
|
|
|
|
bool safe;
|
|
|
|
|
2014-04-02 20:09:53 +02:00
|
|
|
/** Conditional value */
|
|
|
|
bool conditional;
|
|
|
|
|
2021-11-25 18:40:15 +01:00
|
|
|
/** Value is is from an expanded macro */
|
|
|
|
bool macro;
|
|
|
|
|
2015-02-01 15:23:15 +01:00
|
|
|
/** Is this value passed as default parameter to the function? */
|
2015-02-01 15:05:00 +01:00
|
|
|
bool defaultArg;
|
2018-11-10 21:30:01 +01:00
|
|
|
|
2019-08-17 07:36:41 +02:00
|
|
|
int indirect;
|
|
|
|
|
2020-02-17 10:31:08 +01:00
|
|
|
/** Path id */
|
|
|
|
MathLib::bigint path;
|
|
|
|
|
2021-06-04 17:17:41 +02:00
|
|
|
/** int value before implicit truncation */
|
|
|
|
long long wideintvalue;
|
|
|
|
|
2021-10-30 07:43:37 +02:00
|
|
|
std::vector<std::string> subexpressions;
|
|
|
|
|
2022-04-30 09:36:28 +02:00
|
|
|
// Set to where a lifetime is captured by value
|
|
|
|
const Token* capturetok;
|
|
|
|
|
2021-06-04 21:41:30 +02:00
|
|
|
enum class LifetimeKind {
|
|
|
|
// Pointer points to a member of lifetime
|
2021-06-05 08:53:15 +02:00
|
|
|
Object,
|
2021-06-04 21:41:30 +02:00
|
|
|
// A member of object points to the lifetime
|
2021-06-05 08:53:15 +02:00
|
|
|
SubObject,
|
2021-07-02 17:41:51 +02:00
|
|
|
// Lambda has captured lifetime(similar to SubObject)
|
2021-06-05 08:53:15 +02:00
|
|
|
Lambda,
|
2021-07-02 17:41:51 +02:00
|
|
|
// Iterator points to the lifetime of a container(similar to Object)
|
2021-06-05 08:53:15 +02:00
|
|
|
Iterator,
|
2021-06-04 21:41:30 +02:00
|
|
|
// A pointer that holds the address of the lifetime
|
|
|
|
Address
|
|
|
|
} lifetimeKind;
|
2015-07-16 17:33:16 +02:00
|
|
|
|
2021-12-04 17:00:55 +01:00
|
|
|
enum class LifetimeScope { Local, Argument, SubFunction, ThisPointer, ThisValue } lifetimeScope;
|
2019-01-29 09:47:52 +01:00
|
|
|
|
2020-05-10 20:32:59 +02:00
|
|
|
static const char* toString(MoveKind moveKind);
|
2021-06-04 21:41:30 +02:00
|
|
|
static const char* toString(LifetimeKind lifetimeKind);
|
2021-08-15 08:02:31 +02:00
|
|
|
static const char* toString(LifetimeScope lifetimeScope);
|
|
|
|
static const char* toString(Bound bound);
|
2016-11-20 15:14:49 +01:00
|
|
|
|
2015-07-16 17:33:16 +02:00
|
|
|
/** How known is this value */
|
2018-12-31 17:05:46 +01:00
|
|
|
enum class ValueKind {
|
2015-07-16 17:33:16 +02:00
|
|
|
/** This value is possible, other unlisted values may also be possible */
|
|
|
|
Possible,
|
|
|
|
/** Only listed values are possible */
|
2017-09-20 22:41:36 +02:00
|
|
|
Known,
|
|
|
|
/** Inconclusive */
|
2019-09-20 15:06:37 +02:00
|
|
|
Inconclusive,
|
|
|
|
/** Listed values are impossible */
|
|
|
|
Impossible
|
2015-07-16 17:33:16 +02:00
|
|
|
} valueKind;
|
2015-07-25 19:36:29 +02:00
|
|
|
|
|
|
|
void setKnown() {
|
|
|
|
valueKind = ValueKind::Known;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isKnown() const {
|
|
|
|
return valueKind == ValueKind::Known;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setPossible() {
|
|
|
|
valueKind = ValueKind::Possible;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isPossible() const {
|
|
|
|
return valueKind == ValueKind::Possible;
|
|
|
|
}
|
|
|
|
|
2019-09-20 15:07:27 +02:00
|
|
|
bool isImpossible() const {
|
|
|
|
return valueKind == ValueKind::Impossible;
|
|
|
|
}
|
2019-09-20 15:06:37 +02:00
|
|
|
|
2019-09-20 15:07:27 +02:00
|
|
|
void setImpossible() {
|
|
|
|
valueKind = ValueKind::Impossible;
|
|
|
|
}
|
2019-09-20 15:06:37 +02:00
|
|
|
|
2017-09-20 22:41:36 +02:00
|
|
|
void setInconclusive(bool inconclusive = true) {
|
|
|
|
if (inconclusive)
|
|
|
|
valueKind = ValueKind::Inconclusive;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isInconclusive() const {
|
|
|
|
return valueKind == ValueKind::Inconclusive;
|
|
|
|
}
|
|
|
|
|
2015-07-25 19:36:29 +02:00
|
|
|
void changeKnownToPossible() {
|
|
|
|
if (isKnown())
|
|
|
|
valueKind = ValueKind::Possible;
|
|
|
|
}
|
2017-05-23 11:43:56 +02:00
|
|
|
|
|
|
|
bool errorSeverity() const {
|
|
|
|
return !condition && !defaultArg;
|
|
|
|
}
|
2021-08-19 22:01:55 +02:00
|
|
|
|
|
|
|
static bool sameToken(const Token* tok1, const Token* tok2);
|
2014-01-04 20:57:02 +01:00
|
|
|
};
|
|
|
|
|
2016-05-07 20:18:07 +02:00
|
|
|
/// Constant folding of expression. This can be used before the full ValueFlow has been executed (ValueFlow::setValues).
|
2019-06-16 10:09:38 +02:00
|
|
|
const ValueFlow::Value * valueFlowConstantFoldAST(Token *expr, const Settings *settings);
|
2016-05-07 20:18:07 +02:00
|
|
|
|
|
|
|
/// Perform valueflow analysis.
|
2015-02-01 12:10:20 +01:00
|
|
|
void setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings);
|
2015-07-29 19:54:57 +02:00
|
|
|
|
|
|
|
std::string eitherTheConditionIsRedundant(const Token *condition);
|
Set correct type and size of string and char literals (#2275)
* Set correct type and size of string and char literals
Use that string and char literal tokens store the prefix. This makes
it possible to distinghuish between different type of string literals
(i.e., utf8 encoded strings, utf16, wide strings, etc) which have
different type.
When the tokens holding the string and character values have the correct
type, it is possible to improve Token::getStrSize() to give the correct
result for all string types. Previously, it would return the number of
characters in the string, i.e., it would give the wrong size unless
the type of the string was char*.
Since strings now can have different size (in number of bytes) and
length (in number of elements), add a new helper function that returns
the number of characters. Checkers have been updated to use the correct
functions.
Having the size makes it possible to find more problems with prefixed
strings, and to reduce false positives, for example in the buffer
overflow checker.
Also, improve the stringLiteralWrite error message to also print the
prefix of the string (if there is one).
* Add comment and update string length
2019-10-20 07:11:57 +02:00
|
|
|
|
|
|
|
size_t getSizeOf(const ValueType &vt, const Settings *settings);
|
2021-06-04 17:17:41 +02:00
|
|
|
|
|
|
|
const ValueFlow::Value* findValue(const std::list<ValueFlow::Value>& values,
|
|
|
|
const Settings* settings,
|
|
|
|
std::function<bool(const ValueFlow::Value&)> pred);
|
2021-08-16 09:19:07 +02:00
|
|
|
|
|
|
|
std::vector<ValueFlow::Value> isOutOfBounds(const Value& size, const Token* indexTok, bool possible = true);
|
2014-01-04 20:57:02 +01:00
|
|
|
}
|
|
|
|
|
2022-03-12 06:15:35 +01:00
|
|
|
ValueFlow::Value asImpossible(ValueFlow::Value v);
|
|
|
|
|
2021-12-20 07:28:40 +01:00
|
|
|
bool isContainerSizeChanged(const Token* tok, const Settings* settings = nullptr, int depth = 20);
|
|
|
|
|
2019-09-11 19:25:09 +02:00
|
|
|
struct LifetimeToken {
|
|
|
|
const Token* token;
|
|
|
|
bool addressOf;
|
|
|
|
ValueFlow::Value::ErrorPath errorPath;
|
|
|
|
bool inconclusive;
|
|
|
|
|
|
|
|
LifetimeToken() : token(nullptr), addressOf(false), errorPath(), inconclusive(false) {}
|
|
|
|
|
|
|
|
LifetimeToken(const Token* token, ValueFlow::Value::ErrorPath errorPath)
|
|
|
|
: token(token), addressOf(false), errorPath(std::move(errorPath)), inconclusive(false)
|
|
|
|
{}
|
|
|
|
|
|
|
|
LifetimeToken(const Token* token, bool addressOf, ValueFlow::Value::ErrorPath errorPath)
|
|
|
|
: token(token), addressOf(addressOf), errorPath(std::move(errorPath)), inconclusive(false)
|
|
|
|
{}
|
|
|
|
|
|
|
|
static std::vector<LifetimeToken> setAddressOf(std::vector<LifetimeToken> v, bool b) {
|
|
|
|
for (LifetimeToken& x : v)
|
|
|
|
x.addressOf = b;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::vector<LifetimeToken> setInconclusive(std::vector<LifetimeToken> v, bool b) {
|
|
|
|
for (LifetimeToken& x : v)
|
|
|
|
x.inconclusive = b;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-01-11 08:00:13 +01:00
|
|
|
const Token *parseCompareInt(const Token *tok, ValueFlow::Value &true_value, ValueFlow::Value &false_value, const std::function<std::vector<MathLib::bigint>(const Token*)>& evaluate);
|
2019-10-30 17:57:46 +01:00
|
|
|
const Token *parseCompareInt(const Token *tok, ValueFlow::Value &true_value, ValueFlow::Value &false_value);
|
|
|
|
|
2021-03-30 14:02:28 +02:00
|
|
|
ValueFlow::Value inferCondition(std::string op, MathLib::bigint val, const Token* varTok);
|
|
|
|
ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, MathLib::bigint val);
|
|
|
|
|
2022-01-04 15:38:37 +01:00
|
|
|
CPPCHECKLIB ValuePtr<InferModel> makeIntegralInferModel();
|
2021-10-30 22:13:58 +02:00
|
|
|
|
2022-05-04 05:59:01 +02:00
|
|
|
const Token* solveExprValue(const Token* expr,
|
|
|
|
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
|
|
|
|
ValueFlow::Value& value);
|
|
|
|
|
2020-09-07 10:52:54 +02:00
|
|
|
std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
|
2021-08-07 20:51:18 +02:00
|
|
|
bool escape = false,
|
|
|
|
ValueFlow::Value::ErrorPath errorPath = ValueFlow::Value::ErrorPath{});
|
2021-04-30 17:47:08 +02:00
|
|
|
|
|
|
|
bool hasLifetimeToken(const Token* tok, const Token* lifetime);
|
2019-09-11 19:25:09 +02:00
|
|
|
|
2019-09-02 06:58:09 +02:00
|
|
|
const Variable* getLifetimeVariable(const Token* tok, ValueFlow::Value::ErrorPath& errorPath, bool* addressOf = nullptr);
|
2019-01-23 07:29:16 +01:00
|
|
|
|
2020-05-31 10:10:10 +02:00
|
|
|
const Variable* getLifetimeVariable(const Token* tok);
|
|
|
|
|
2019-05-05 11:40:59 +02:00
|
|
|
bool isLifetimeBorrowed(const Token *tok, const Settings *settings);
|
|
|
|
|
2019-01-29 09:47:52 +01:00
|
|
|
std::string lifetimeType(const Token *tok, const ValueFlow::Value *val);
|
|
|
|
|
2019-07-18 10:56:44 +02:00
|
|
|
std::string lifetimeMessage(const Token *tok, const ValueFlow::Value *val, ValueFlow::Value::ErrorPath &errorPath);
|
|
|
|
|
2020-12-23 13:37:28 +01:00
|
|
|
CPPCHECKLIB ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive = false);
|
2019-05-31 11:16:04 +02:00
|
|
|
|
2022-01-18 14:48:02 +01:00
|
|
|
CPPCHECKLIB std::vector<ValueFlow::Value> getLifetimeObjValues(const Token* tok,
|
|
|
|
bool inconclusive = false,
|
|
|
|
MathLib::bigint path = 0);
|
2021-01-05 16:56:38 +01:00
|
|
|
|
2022-02-22 09:51:44 +01:00
|
|
|
const Token* getEndOfExprScope(const Token* tok, const Scope* defaultScope = nullptr, bool smallest = true);
|
|
|
|
|
2014-01-04 20:57:02 +01:00
|
|
|
#endif // valueflowH
|