| 241 | } |
| 242 | |
| 243 | static std::vector<ValueFlow::Value> getOverrunIndexValues(const Token* tok, |
| 244 | const Token* arrayToken, |
| 245 | const std::vector<Dimension>& dimensions, |
| 246 | const std::vector<const Token*>& indexTokens, |
| 247 | MathLib::bigint path) |
| 248 | { |
| 249 | const Token *array = arrayToken; |
| 250 | while (Token::Match(array, ".|::")) |
| 251 | array = array->astOperand2(); |
| 252 | |
| 253 | bool isArrayIndex = tok->str() == "["; |
| 254 | if (isArrayIndex) { |
| 255 | const Token* parent = tok; |
| 256 | while (Token::simpleMatch(parent, "[")) |
| 257 | parent = parent->astParent(); |
| 258 | if (!parent || parent->isUnaryOp("&")) |
| 259 | isArrayIndex = false; |
| 260 | } |
| 261 | |
| 262 | bool overflow = false; |
| 263 | std::vector<ValueFlow::Value> indexValues; |
| 264 | for (std::size_t i = 0; i < dimensions.size() && i < indexTokens.size(); ++i) { |
| 265 | MathLib::bigint size = dimensions[i].num; |
| 266 | if (!isArrayIndex) |
| 267 | size++; |
| 268 | const bool zeroArray = array->variable() && array->variable()->isArray() && dimensions[i].num == 0; |
| 269 | std::vector<ValueFlow::Value> values = !zeroArray |
| 270 | ? ValueFlow::isOutOfBounds(makeSizeValue(size, path), indexTokens[i]) |
| 271 | : std::vector<ValueFlow::Value>{}; |
| 272 | if (values.empty()) { |
| 273 | if (const ValueFlow::Value* v = indexTokens[i]->getKnownValue(ValueFlow::Value::ValueType::INT)) |
| 274 | indexValues.push_back(*v); |
| 275 | else |
| 276 | indexValues.push_back(ValueFlow::Value::unknown()); |
| 277 | continue; |
| 278 | } |
| 279 | overflow = true; |
| 280 | indexValues.push_back(values.front()); |
| 281 | } |
| 282 | if (overflow) |
| 283 | return indexValues; |
| 284 | return {}; |
| 285 | } |
| 286 | |
| 287 | void CheckBufferOverrunImpl::arrayIndex() |
| 288 | { |
no test coverage detected