[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/cppcheck-opensource/cppcheck/main/lib/checktype.cpp [Back]  [Original]

/*
 * Cppcheck - A tool for static C/C++ code analysis
 * Copyright (C) 2007-2026 Cppcheck team.
 *
 * 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 .
 */


//---------------------------------------------------------------------------
#include "checktype.h"

#include "astutils.h"
#include "errortypes.h"
#include "mathlib.h"
#include "platform.h"
#include "settings.h"
#include "standards.h"
#include "symboldatabase.h"
#include "token.h"
#include "tokenize.h"
#include "valueflow.h"
#include "vfvalue.h"

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Checking for shift by too many bits
//---------------------------------------------------------------------------
//

// CWE ids used:
static const CWE CWE195(195U);   // Signed to Unsigned Conversion Error
static const CWE CWE197(197U);   // Numeric Truncation Error
static const CWE CWE758(758U);   // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior
static const CWE CWE190(190U);   // Integer Overflow or Wraparound


void CheckTypeImpl::checkTooBigBitwiseShift()
{
    // unknown sizeof(int) => can't run this checker
    if (mSettings.platform.type == Platform::Type::Unspecified)
        return;

    logChecker("CheckType::checkTooBigBitwiseShift"); // platform

    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
        // C++ and macro: OUT(xlinkAt(2), ") ;") && tok->next()->isUpperCaseName() && !tok->next()->function())
            tok = tok->linkAt(2);

        tok = skipUnreachableBranch(tok);

        if (!tok->astOperand1() || !tok->astOperand2())
            continue;

        if (!Token::Match(tok, "|="))
            continue;

        // get number of bits of lhs
        const ValueType * const lhstype = tok->astOperand1()->valueType();
        if (!lhstype || !lhstype->isIntegral() || lhstype->pointer >= 1)
            continue;
        // C11 Standard, section 6.5.7 Bitwise shift operators, states:
        //   The integer promotions are performed on each of the operands.
        //   The type of the result is that of the promoted left operand.
        std::uint8_t lhsbits;
        if ((lhstype->type == ValueType::Type::CHAR) ||
            (lhstype->type == ValueType::Type::SHORT) ||
            (lhstype->type == ValueType::Type::WCHAR_T) ||
            (lhstype->type == ValueType::Type::BOOL) ||
            (lhstype->type == ValueType::Type::INT))
            lhsbits = mSettings.platform.int_bit;
        else if (lhstype->type == ValueType::Type::LONG)
            lhsbits = mSettings.platform.long_bit;
        else if (lhstype->type == ValueType::Type::LONGLONG)
            lhsbits = mSettings.platform.long_long_bit;
        else
            continue;

        // Get biggest rhs value. preferably a value which doesn't have 'condition'.
        const ValueFlow::Value * value = tok->astOperand2()->getValueGE(lhsbits, mSettings);
        if (value && mSettings.isEnabled(value, false))
            tooBigBitwiseShiftError(tok, lhsbits, *value);
        else if (lhstype->sign == ValueType::Sign::SIGNED) {
            value = tok->astOperand2()->getValueGE(lhsbits-1, mSettings);
            if (value && mSettings.isEnabled(value, false))
                tooBigSignedBitwiseShiftError(tok, lhsbits, *value);
        }
    }
}

void CheckTypeImpl::tooBigBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits)
{
    constexpr char id[] = "shiftTooManyBits";

    if (!tok) {
        reportError(tok, Severity::error, id, "Shifting 32-bit value by 40 bits is undefined behaviour", CWE758, Certainty::normal);
        return;
    }

    ErrorPath errorPath = getErrorPath(tok, &rhsbits, "Shift");

    std::ostringstream errmsg;
    errmsg str() == " 'l = (" + tgtStr + ")a * b;'.", CWE197, Certainty::normal);
}

void CheckTypeImpl::longCastReturnError(const Token *tok, const ValueType* src, const ValueType* tgt)
{
    std::string srcStr = src ? src->str() : "int";
    makeBaseTypeString(srcStr);
    std::string tgtStr = tgt ? tgt->str() : "long";
    makeBaseTypeString(tgtStr);
    reportError(tok,
                Severity::style,
                "truncLongCastReturn",
                srcStr +" result is returned as " + tgtStr + " value. If the return value is " + tgtStr + " to avoid loss of information, then you have loss of information.\n" +
                srcStr +" result is returned as " + tgtStr + " value. If the return value is " + tgtStr + " 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);
}

//---------------------------------------------------------------------------
// Checking for float to integer overflow
//---------------------------------------------------------------------------

void CheckTypeImpl::checkFloatToIntegerOverflow()
{
    logChecker("CheckType::checkFloatToIntegerOverflow");

    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
        const ValueType *vtint, *vtfloat;

        // Explicit cast
        if (Token::Match(tok, "( %name%") && tok->astOperand1() && !tok->astOperand2()) {
            if (isUnreachableOperand(tok))
                continue;
            vtint = tok->valueType();
            vtfloat = tok->astOperand1()->valueType();
            checkFloatToIntegerOverflow(tok, vtint, vtfloat, tok->astOperand1()->values());
        }

        // Assignment
        else if (tok->str() == "=" && tok->astOperand1() && tok->astOperand2()) {
            if (isUnreachableOperand(tok))
                continue;
            vtint = tok->astOperand1()->valueType();
            vtfloat = tok->astOperand2()->valueType();
            checkFloatToIntegerOverflow(tok, vtint, vtfloat, tok->astOperand2()->values());
        }

        else if (tok->str() == "return" && tok->astOperand1() && tok->astOperand1()->valueType() && tok->astOperand1()->valueType()->isFloat()) {
            if (isUnreachableOperand(tok))
                continue;
            const Scope *scope = tok->scope();
            while (scope && scope->type != ScopeType::eLambda && scope->type != ScopeType::eFunction)
                scope = scope->nestedIn;
            if (scope && scope->type == ScopeType::eFunction && scope->function && scope->function->retDef) {
                const ValueType &valueType = ValueType::parseDecl(scope->function->retDef, mSettings);
                vtfloat = tok->astOperand1()->valueType();
                checkFloatToIntegerOverflow(tok, &valueType, vtfloat, tok->astOperand1()->values());
            }
        }
    }
}

void CheckTypeImpl::checkFloatToIntegerOverflow(const Token *tok, const ValueType *vtint, const ValueType *vtfloat, const std::list &floatValues)
{
    // Conversion of float to integer?
    if (!vtint || !vtint->isIntegral())
        return;
    if (!vtfloat || !vtfloat->isFloat())
        return;

    for (const ValueFlow::Value &f : floatValues) {
        if (f.valueType != ValueFlow::Value::ValueType::FLOAT)
            continue;
        if (!mSettings.isEnabled(&f, false))
            continue;
        if (f.floatValue >= std::exp2(mSettings.platform.long_long_bit))
            floatToIntegerOverflowError(tok, f);
        else if ((-f.floatValue) > std::exp2(mSettings.platform.long_long_bit - 1))
            floatToIntegerOverflowError(tok, f);
        else if (mSettings.platform.type != Platform::Type::Unspecified) {
            int bits = 0;
            if (vtint->type == ValueType::Type::CHAR)
                bits = mSettings.platform.char_bit;
            else if (vtint->type == ValueType::Type::SHORT)
                bits = mSettings.platform.short_bit;
            else if (vtint->type == ValueType::Type::INT)
                bits = mSettings.platform.int_bit;
            else if (vtint->type == ValueType::Type::LONG)
                bits = mSettings.platform.long_bit;
            else if (vtint->type == ValueType::Type::LONGLONG)
                bits = mSettings.platform.long_long_bit;
            else
                continue;
            if (bits < MathLib::bigint_bits && f.floatValue >= (1ULL 

Web Proxy Viewer  |  New URL  |  Original Page