Cppcheck
check64bit.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2023 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 //---------------------------------------------------------------------------
20 // 64-bit portability
21 //---------------------------------------------------------------------------
22 
23 #include "check64bit.h"
24 
25 #include "errortypes.h"
26 #include "settings.h"
27 #include "symboldatabase.h"
28 #include "token.h"
29 #include "tokenize.h"
30 
31 #include <vector>
32 
33 //---------------------------------------------------------------------------
34 
35 // CWE ids used
36 static const CWE CWE758(758U); // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior
37 
38 // Register this check class (by creating a static instance of it)
39 namespace {
40  Check64BitPortability instance;
41 }
42 
44 {
46  return;
47 
48  logChecker("Check64BitPortability::pointerassignment"); // portability
49 
50  const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
51 
52  // Check return values
53  for (const Scope * scope : symbolDatabase->functionScopes) {
54  if (scope->function == nullptr || !scope->function->hasBody()) // We only look for functions with a body
55  continue;
56 
57  bool retPointer = false;
58  if (scope->function->token->strAt(-1) == "*") // Function returns a pointer
59  retPointer = true;
60  else if (Token::Match(scope->function->token->previous(), "int|long|DWORD")) // Function returns an integer
61  ;
62  else
63  continue;
64 
65  for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
66  // skip nested functions
67  if (tok->str() == "{") {
68  if (tok->scope()->type == Scope::ScopeType::eFunction || tok->scope()->type == Scope::ScopeType::eLambda)
69  tok = tok->link();
70  }
71 
72  if (tok->str() != "return")
73  continue;
74 
75  if (!tok->astOperand1() || tok->astOperand1()->isNumber())
76  continue;
77 
78  const ValueType * const returnType = tok->astOperand1()->valueType();
79  if (!returnType)
80  continue;
81 
82  if (retPointer && !returnType->typeScope && returnType->pointer == 0U)
83  returnIntegerError(tok);
84 
85  if (!retPointer && returnType->pointer >= 1U)
86  returnPointerError(tok);
87  }
88  }
89 
90  // Check assignments
91  for (const Scope * scope : symbolDatabase->functionScopes) {
92  for (const Token *tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) {
93  if (tok->str() != "=")
94  continue;
95 
96  const ValueType *lhstype = tok->astOperand1() ? tok->astOperand1()->valueType() : nullptr;
97  const ValueType *rhstype = tok->astOperand2() ? tok->astOperand2()->valueType() : nullptr;
98  if (!lhstype || !rhstype)
99  continue;
100 
101  // Assign integer to pointer..
102  if (lhstype->pointer >= 1U &&
103  !tok->astOperand2()->isNumber() &&
104  rhstype->pointer == 0U &&
105  rhstype->originalTypeName.empty() &&
106  rhstype->type == ValueType::Type::INT)
108 
109  // Assign pointer to integer..
110  if (rhstype->pointer >= 1U &&
111  lhstype->pointer == 0U &&
112  lhstype->originalTypeName.empty() &&
113  lhstype->isIntegral() &&
114  lhstype->type >= ValueType::Type::CHAR &&
115  lhstype->type <= ValueType::Type::INT)
117  }
118  }
119 }
120 
122 {
124  "AssignmentAddressToInteger",
125  "Assigning a pointer to an integer is not portable.\n"
126  "Assigning a pointer to an integer (int/long/etc) is not portable across different platforms and "
127  "compilers. For example in 32-bit Windows and linux they are same width, but in 64-bit Windows and linux "
128  "they are of different width. In worst case you end up assigning 64-bit address to 32-bit integer. The safe "
129  "way is to store addresses only in pointer types (or typedefs like uintptr_t).", CWE758, Certainty::normal);
130 }
131 
133 {
135  "AssignmentIntegerToAddress",
136  "Assigning an integer to a pointer is not portable.\n"
137  "Assigning an integer (int/long/etc) to a pointer is not portable across different platforms and "
138  "compilers. For example in 32-bit Windows and linux they are same width, but in 64-bit Windows and linux "
139  "they are of different width. In worst case you end up assigning 64-bit integer to 32-bit pointer. The safe "
140  "way is to store addresses only in pointer types (or typedefs like uintptr_t).", CWE758, Certainty::normal);
141 }
142 
144 {
146  "CastAddressToIntegerAtReturn",
147  "Returning an address value in a function with integer return type is not portable.\n"
148  "Returning an address value in a function with integer (int/long/etc) return type is not portable across "
149  "different platforms and compilers. For example in 32-bit Windows and Linux they are same width, but in "
150  "64-bit Windows and Linux they are of different width. In worst case you end up casting 64-bit address down "
151  "to 32-bit integer. The safe way is to always return an integer.", CWE758, Certainty::normal);
152 }
153 
155 {
157  "CastIntegerToAddressAtReturn",
158  "Returning an integer in a function with pointer return type is not portable.\n"
159  "Returning an integer (int/long/etc) in a function with pointer return type is not portable across different "
160  "platforms and compilers. For example in 32-bit Windows and Linux they are same width, but in 64-bit Windows "
161  "and Linux they are of different width. In worst case you end up casting 64-bit integer down to 32-bit pointer. "
162  "The safe way is to always return a pointer.", CWE758, Certainty::normal);
163 }
static const CWE CWE758(758U)
Check for 64-bit portability issues.
Definition: check64bit.h:43
void assignmentAddressToIntegerError(const Token *tok)
Definition: check64bit.cpp:121
void returnIntegerError(const Token *tok)
Definition: check64bit.cpp:154
void assignmentIntegerToAddressError(const Token *tok)
Definition: check64bit.cpp:132
void returnPointerError(const Token *tok)
Definition: check64bit.cpp:143
void pointerassignment()
Check for pointer assignment.
Definition: check64bit.cpp:43
void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg)
report an error
Definition: check.h:138
const Settings *const mSettings
Definition: check.h:134
const Tokenizer *const mTokenizer
Definition: check.h:133
void logChecker(const char id[])
log checker
Definition: check.cpp:129
bool hasBody() const
const Token * token
function name token in implementation
Function * function
function info for this function
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
SimpleEnableGroup< Severity > severity
Definition: settings.h:358
bool isEnabled(T flag) const
Definition: settings.h:66
std::vector< const Scope * > functionScopes
Fast access to function scopes.
The token list that the TokenList generates is a linked-list of this class.
Definition: token.h:150
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
Definition: token.cpp:722
const std::string & strAt(int index) const
Definition: token.cpp:457
Token * previous()
Definition: token.h:862
Token * next()
Definition: token.h:830
const SymbolDatabase * getSymbolDatabase() const
Definition: tokenize.h:563
Value type.
enum ValueType::Type type
bool isIntegral() const
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
std::string originalTypeName
original type name as written in the source code.
const Scope * typeScope
if the type definition is seen this point out the type scope
@ portability
Portability warning.