/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 | } |