| 465 | //--------------------------------------------------------------------------- |
| 466 | |
| 467 | void CheckBufferOverrunImpl::pointerArithmetic() |
| 468 | { |
| 469 | if (!mSettings.severity.isEnabled(Severity::portability) && !mSettings.isPremiumEnabled("pointerOutOfBounds")) |
| 470 | return; |
| 471 | |
| 472 | logChecker("CheckBufferOverrun::pointerArithmetic"); // portability |
| 473 | |
| 474 | for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) { |
| 475 | if (!Token::Match(tok, "+|-")) |
| 476 | continue; |
| 477 | if (!tok->valueType() || tok->valueType()->pointer == 0) |
| 478 | continue; |
| 479 | if (!tok->isBinaryOp()) |
| 480 | continue; |
| 481 | if (!tok->astOperand1()->valueType() || !tok->astOperand2()->valueType()) |
| 482 | continue; |
| 483 | |
| 484 | const Token *arrayToken, *indexToken; |
| 485 | if (tok->astOperand1()->valueType()->pointer > 0) { |
| 486 | arrayToken = tok->astOperand1(); |
| 487 | indexToken = tok->astOperand2(); |
| 488 | } else { |
| 489 | arrayToken = tok->astOperand2(); |
| 490 | indexToken = tok->astOperand1(); |
| 491 | } |
| 492 | |
| 493 | if (!indexToken || !indexToken->valueType() || indexToken->valueType()->pointer > 0 || !indexToken->valueType()->isIntegral()) |
| 494 | continue; |
| 495 | |
| 496 | std::vector<Dimension> dimensions; |
| 497 | ErrorPath errorPath; |
| 498 | bool mightBeLarger = false; |
| 499 | MathLib::bigint path = 0; |
| 500 | if (!getDimensionsEtc(arrayToken, mSettings, dimensions, errorPath, mightBeLarger, path)) |
| 501 | continue; |
| 502 | |
| 503 | if (tok->str() == "+") { |
| 504 | // Positive index |
| 505 | if (!mightBeLarger) { // TODO check arrays with dim 1 also |
| 506 | const std::vector<const Token *> indexTokens{indexToken}; |
| 507 | const std::vector<ValueFlow::Value>& indexValues = |
| 508 | getOverrunIndexValues(tok, arrayToken, dimensions, indexTokens, path); |
| 509 | if (!indexValues.empty() && !isUnreachableOperand(tok)) |
| 510 | pointerArithmeticError(tok, indexToken, &indexValues.front()); |
| 511 | } |
| 512 | |
| 513 | if (const ValueFlow::Value *neg = indexToken->getValueLE(-1, mSettings)) |
| 514 | pointerArithmeticError(tok, indexToken, neg); |
| 515 | } else if (tok->str() == "-") { |
| 516 | if (arrayToken->variable() && arrayToken->variable()->isArgument()) |
| 517 | continue; |
| 518 | |
| 519 | const Token *array = arrayToken; |
| 520 | while (Token::Match(array, ".|::")) |
| 521 | array = array->astOperand2(); |
| 522 | if (array->variable() && array->variable()->isArray()) { |
| 523 | const ValueFlow::Value *v = indexToken->getValueGE(1, mSettings); |
| 524 | if (v) |
no test coverage detected