Coverage Report

Created: 2025-01-24 06:31

/src/cppcheck/oss-fuzz/build/check64bit.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "matchcompiler.h"
2
#include <string>
3
#include <cstring>
4
#include "errorlogger.h"
5
#include "token.h"
6
// pattern: int|long|DWORD
7
1.10k
static inline bool match1(const Token* tok) {
8
1.10k
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("int")) || (tok->str() == MatchCompiler::makeConstString("long")) || (tok->str() == MatchCompiler::makeConstString("DWORD"))))
9
0
        return false;
10
1.10k
    return true;
11
1.10k
}
12
/*
13
 * Cppcheck - A tool for static C/C++ code analysis
14
 * Copyright (C) 2007-2023 Cppcheck team.
15
 *
16
 * This program is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU General Public License as published by
18
 * the Free Software Foundation, either version 3 of the License, or
19
 * (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
 */
29
30
//---------------------------------------------------------------------------
31
// 64-bit portability
32
//---------------------------------------------------------------------------
33
34
#include "check64bit.h"
35
36
#include "errortypes.h"
37
#include "settings.h"
38
#include "symboldatabase.h"
39
#include "token.h"
40
#include "tokenize.h"
41
42
#include <vector>
43
44
//---------------------------------------------------------------------------
45
46
// CWE ids used
47
static const CWE CWE758(758U);   // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior
48
49
// Register this check class (by creating a static instance of it)
50
namespace {
51
    Check64BitPortability instance;
52
}
53
54
void Check64BitPortability::pointerassignment()
55
764
{
56
764
    if (!mSettings->severity.isEnabled(Severity::portability))
57
0
        return;
58
59
764
    logChecker("Check64BitPortability::pointerassignment"); // portability
60
61
764
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
62
63
    // Check return values
64
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
65
1.10k
        if (scope->function == nullptr || !scope->function->hasBody()) // We only look for functions with a body
66
0
            continue;
67
68
1.10k
        bool retPointer = false;
69
1.10k
        if (scope->function->token->strAt(-1) == MatchCompiler::makeConstString("*")) // Function returns a pointer
70
0
            retPointer = true;
71
1.10k
        else if (match1(scope->function->token->previous())) // Function returns an integer
72
1.10k
            ;
73
0
        else
74
0
            continue;
75
76
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
77
            // skip nested functions
78
21.5k
            if (tok->str() == MatchCompiler::makeConstString("{")) {
79
931
                if (tok->scope()->type == Scope::ScopeType::eFunction || tok->scope()->type == Scope::ScopeType::eLambda)
80
0
                    tok = tok->link();
81
931
            }
82
83
21.5k
            if (tok->str() != MatchCompiler::makeConstString("return"))
84
20.3k
                continue;
85
86
1.19k
            if (!tok->astOperand1() || tok->astOperand1()->isNumber())
87
776
                continue;
88
89
416
            const ValueType * const returnType = tok->astOperand1()->valueType();
90
416
            if (!returnType)
91
144
                continue;
92
93
272
            if (retPointer && !returnType->typeScope && returnType->pointer == 0U)
94
0
                returnIntegerError(tok);
95
96
272
            if (!retPointer && returnType->pointer >= 1U)
97
0
                returnPointerError(tok);
98
272
        }
99
1.10k
    }
100
101
    // Check assignments
102
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
103
23.7k
        for (const Token *tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) {
104
22.6k
            if (tok->str() != MatchCompiler::makeConstString("="))
105
20.4k
                continue;
106
107
2.24k
            const ValueType *lhstype = tok->astOperand1() ? tok->astOperand1()->valueType() : nullptr;
108
2.24k
            const ValueType *rhstype = tok->astOperand2() ? tok->astOperand2()->valueType() : nullptr;
109
2.24k
            if (!lhstype || !rhstype)
110
2.02k
                continue;
111
112
            // Assign integer to pointer..
113
224
            if (lhstype->pointer >= 1U &&
114
224
                !tok->astOperand2()->isNumber() &&
115
224
                rhstype->pointer == 0U &&
116
224
                rhstype->originalTypeName.empty() &&
117
224
                rhstype->type == ValueType::Type::INT)
118
0
                assignmentIntegerToAddressError(tok);
119
120
            // Assign pointer to integer..
121
224
            if (rhstype->pointer >= 1U &&
122
224
                lhstype->pointer == 0U &&
123
224
                lhstype->originalTypeName.empty() &&
124
224
                lhstype->isIntegral() &&
125
224
                lhstype->type >= ValueType::Type::CHAR &&
126
224
                lhstype->type <= ValueType::Type::INT)
127
0
                assignmentAddressToIntegerError(tok);
128
224
        }
129
1.10k
    }
130
764
}
131
132
void Check64BitPortability::assignmentAddressToIntegerError(const Token *tok)
133
0
{
134
0
    reportError(tok, Severity::portability,
135
0
                "AssignmentAddressToInteger",
136
0
                "Assigning a pointer to an integer is not portable.\n"
137
0
                "Assigning a pointer to an integer (int/long/etc) is not portable across different platforms and "
138
0
                "compilers. For example in 32-bit Windows and linux they are same width, but in 64-bit Windows and linux "
139
0
                "they are of different width. In worst case you end up assigning 64-bit address to 32-bit integer. The safe "
140
0
                "way is to store addresses only in pointer types (or typedefs like uintptr_t).", CWE758, Certainty::normal);
141
0
}
142
143
void Check64BitPortability::assignmentIntegerToAddressError(const Token *tok)
144
0
{
145
0
    reportError(tok, Severity::portability,
146
0
                "AssignmentIntegerToAddress",
147
0
                "Assigning an integer to a pointer is not portable.\n"
148
0
                "Assigning an integer (int/long/etc) to a pointer is not portable across different platforms and "
149
0
                "compilers. For example in 32-bit Windows and linux they are same width, but in 64-bit Windows and linux "
150
0
                "they are of different width. In worst case you end up assigning 64-bit integer to 32-bit pointer. The safe "
151
0
                "way is to store addresses only in pointer types (or typedefs like uintptr_t).", CWE758, Certainty::normal);
152
0
}
153
154
void Check64BitPortability::returnPointerError(const Token *tok)
155
0
{
156
0
    reportError(tok, Severity::portability,
157
0
                "CastAddressToIntegerAtReturn",
158
0
                "Returning an address value in a function with integer return type is not portable.\n"
159
0
                "Returning an address value in a function with integer (int/long/etc) return type is not portable across "
160
0
                "different platforms and compilers. For example in 32-bit Windows and Linux they are same width, but in "
161
0
                "64-bit Windows and Linux they are of different width. In worst case you end up casting 64-bit address down "
162
0
                "to 32-bit integer. The safe way is to always return an integer.", CWE758, Certainty::normal);
163
0
}
164
165
void Check64BitPortability::returnIntegerError(const Token *tok)
166
0
{
167
0
    reportError(tok, Severity::portability,
168
0
                "CastIntegerToAddressAtReturn",
169
0
                "Returning an integer in a function with pointer return type is not portable.\n"
170
0
                "Returning an integer (int/long/etc) in a function with pointer return type is not portable across different "
171
0
                "platforms and compilers. For example in 32-bit Windows and Linux they are same width, but in 64-bit Windows "
172
0
                "and Linux they are of different width. In worst case you end up casting 64-bit integer down to 32-bit pointer. "
173
0
                "The safe way is to always return a pointer.", CWE758, Certainty::normal);
174
0
}
175
176
void Check64BitPortability::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
177
764
{
178
764
    Check64BitPortability check64BitPortability(&tokenizer, &tokenizer.getSettings(), errorLogger);
179
764
    check64BitPortability.pointerassignment();
180
764
}
181
182
void Check64BitPortability::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
183
0
{
184
0
    Check64BitPortability c(nullptr, settings, errorLogger);
185
0
    c.assignmentAddressToIntegerError(nullptr);
186
0
    c.assignmentIntegerToAddressError(nullptr);
187
0
    c.returnIntegerError(nullptr);
188
0
    c.returnPointerError(nullptr);
189
0
}