Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions lib/check64bit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ namespace {
Check64BitPortability instance;
}

static bool is32BitIntegerReturn(const Function* func, const Settings* settings)
{
if (settings->platform.sizeof_pointer != 8)
return false;
const ValueType* vt = func->arg->valueType();
return vt && vt->pointer == 0 && vt->isIntegral() && vt->typeSize(settings->platform) == 4;
}

void Check64BitPortability::pointerassignment()
{
if (!mSettings->severity.isEnabled(Severity::portability))
Expand All @@ -57,7 +65,7 @@ void Check64BitPortability::pointerassignment()
bool retPointer = false;
if (scope->function->token->strAt(-1) == "*") // Function returns a pointer
retPointer = true;
else if (Token::Match(scope->function->token->previous(), "int|long|DWORD")) // Function returns an integer
else if (is32BitIntegerReturn(scope->function, mSettings))
;
else
continue;
Expand All @@ -82,8 +90,17 @@ void Check64BitPortability::pointerassignment()
if (retPointer && !returnType->typeScope && returnType->pointer == 0U)
returnIntegerError(tok);

if (!retPointer && returnType->pointer >= 1U)
returnPointerError(tok);
if (!retPointer) {
bool warn = returnType->pointer >= 1U;
if (!warn) {
const Token* tok2 = tok->astOperand1();
while (tok2 && tok2->isCast())
tok2 = tok2->astOperand2() ? tok2->astOperand2() : tok2->astOperand1();
warn = tok2 && tok2->valueType() && tok2->valueType()->pointer;
}
if (warn)
returnPointerError(tok);
}
}
}

Expand Down Expand Up @@ -148,7 +165,7 @@ void Check64BitPortability::returnPointerError(const Token *tok)
"Returning an address value in a function with integer (int/long/etc) return type is not portable across "
"different platforms and compilers. For example in 32-bit Windows and Linux they are same width, but in "
"64-bit Windows and Linux they are of different width. In worst case you end up casting 64-bit address down "
"to 32-bit integer. The safe way is to always return an integer.", CWE758, Certainty::normal);
"to 32-bit integer. The safe way is to return a type such as intptr_t.", CWE758, Certainty::normal);
}

void Check64BitPortability::returnIntegerError(const Token *tok)
Expand Down
17 changes: 17 additions & 0 deletions test/test64bit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,23 @@ class Test64BitPortability : public TestFixture {
" return x.get();\n"
"}\n");
ASSERT_EQUALS("", errout_str());

check("int f(int* p) {\n" // #14294
" return (int)p;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2:5]: (portability) Returning an address value in a function with integer return type is not portable. [CastAddressToIntegerAtReturn]\n",
errout_str());

check("int f(int* p) {\n"
" return reinterpret_cast<int>(p);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:2:5]: (portability) Returning an address value in a function with integer return type is not portable. [CastAddressToIntegerAtReturn]\n",
errout_str());

check("bool f(const int* p) {\n"
" return p;\n"
"}\n");
ASSERT_EQUALS("", errout_str());
}
};

Expand Down
Loading