| 756 | //--------------------------------------------------------------------------- |
| 757 | |
| 758 | void CheckBufferOverrunImpl::stringNotZeroTerminated() |
| 759 | { |
| 760 | // this is currently 'inconclusive'. See TestBufferOverrun::terminateStrncpy3 |
| 761 | if (!mSettings.severity.isEnabled(Severity::warning) || !mSettings.certainty.isEnabled(Certainty::inconclusive)) |
| 762 | return; |
| 763 | |
| 764 | logChecker("CheckBufferOverrun::stringNotZeroTerminated"); // warning,inconclusive |
| 765 | |
| 766 | const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); |
| 767 | for (const Scope * const scope : symbolDatabase->functionScopes) { |
| 768 | for (const Token *tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) { |
| 769 | if (!Token::simpleMatch(tok, "strncpy (")) |
| 770 | continue; |
| 771 | const std::vector<const Token *> args = getArguments(tok); |
| 772 | if (args.size() != 3) |
| 773 | continue; |
| 774 | const Token *sizeToken = args[2]; |
| 775 | if (!sizeToken->hasKnownIntValue()) |
| 776 | continue; |
| 777 | const ValueFlow::Value &bufferSize = getBufferSize(args[0]); |
| 778 | if (bufferSize.intvalue < 0 || sizeToken->getKnownIntValue() < bufferSize.intvalue) |
| 779 | continue; |
| 780 | if (Token::simpleMatch(args[1], "(") && Token::simpleMatch(args[1]->astOperand1(), ". c_str") && args[1]->astOperand1()->astOperand1()) { |
| 781 | const std::list<ValueFlow::Value>& contValues = args[1]->astOperand1()->astOperand1()->values(); |
| 782 | auto it = std::find_if(contValues.cbegin(), contValues.cend(), [](const ValueFlow::Value& value) { |
| 783 | return value.isContainerSizeValue() && !value.isImpossible(); |
| 784 | }); |
| 785 | if (it != contValues.end() && it->intvalue < sizeToken->getKnownIntValue()) |
| 786 | continue; |
| 787 | } else { |
| 788 | const Token* srcValue = args[1]->getValueTokenMaxStrLength(); |
| 789 | if (srcValue && Token::getStrLength(srcValue) < sizeToken->getKnownIntValue()) |
| 790 | continue; |
| 791 | } |
| 792 | // Is the buffer zero terminated after the call? |
| 793 | bool isZeroTerminated = false; |
| 794 | for (const Token *tok2 = tok->linkAt(1); tok2 != scope->bodyEnd; tok2 = tok2->next()) { |
| 795 | if (!Token::simpleMatch(tok2, "] =")) |
| 796 | continue; |
| 797 | const Token *rhs = tok2->next()->astOperand2(); |
| 798 | if (!rhs || !rhs->hasKnownIntValue() || rhs->getKnownIntValue() != 0) |
| 799 | continue; |
| 800 | if (isSameExpression(false, args[0], tok2->link()->astOperand1(), mSettings, false, false)) |
| 801 | isZeroTerminated = true; |
| 802 | } |
| 803 | if (isZeroTerminated) |
| 804 | continue; |
| 805 | // TODO: Locate unsafe string usage.. |
| 806 | terminateStrncpyError(tok, getRealBufferTok(args[0])->expressionString()); |
| 807 | } |
| 808 | } |
| 809 | } |
| 810 | |
| 811 | void CheckBufferOverrunImpl::terminateStrncpyError(const Token *tok, const std::string &varname) |
| 812 | { |
no test coverage detected