From cc46f773f9ffe5b9e1fc36af5f0d967784279221 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Sat, 29 Nov 2025 22:12:18 +0100 Subject: [PATCH 1/3] Fix #14294 FN CastAddressToIntegerAtReturn with cast --- lib/check64bit.cpp | 23 +++++++++++++++++++---- test/test64bit.cpp | 12 ++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/lib/check64bit.cpp b/lib/check64bit.cpp index 794795eff26..972c8d4a7a9 100644 --- a/lib/check64bit.cpp +++ b/lib/check64bit.cpp @@ -40,6 +40,12 @@ namespace { Check64BitPortability instance; } +static bool is32BitIntegerReturn(const Function* func, const Settings* settings) +{ + const ValueType* vt = func->arg->valueType(); + return vt && vt->isIntegral() && vt->typeSize(settings->platform) < settings->platform.sizeof_pointer; +} + void Check64BitPortability::pointerassignment() { if (!mSettings->severity.isEnabled(Severity::portability)) @@ -57,7 +63,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; @@ -82,8 +88,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); + } } } @@ -148,7 +163,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) diff --git a/test/test64bit.cpp b/test/test64bit.cpp index 7a05bf75178..4d6cbb8ad65 100644 --- a/test/test64bit.cpp +++ b/test/test64bit.cpp @@ -307,6 +307,18 @@ 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(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()); } }; From 43de9728884e368aa49a8ace07f424ec2d57f6c5 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Sun, 30 Nov 2025 10:06:06 +0100 Subject: [PATCH 2/3] Fix --- lib/check64bit.cpp | 4 +++- test/test64bit.cpp | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/check64bit.cpp b/lib/check64bit.cpp index 972c8d4a7a9..f2eacf8cf44 100644 --- a/lib/check64bit.cpp +++ b/lib/check64bit.cpp @@ -42,8 +42,10 @@ namespace { 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->isIntegral() && vt->typeSize(settings->platform) < settings->platform.sizeof_pointer; + return vt && vt->isIntegral() && vt->typeSize(settings->platform) == 4; } void Check64BitPortability::pointerassignment() diff --git a/test/test64bit.cpp b/test/test64bit.cpp index 4d6cbb8ad65..e3b83c98060 100644 --- a/test/test64bit.cpp +++ b/test/test64bit.cpp @@ -319,6 +319,11 @@ class Test64BitPortability : public TestFixture { "}\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()); } }; From 5ded48c20cce84583efe22f546f71f7d532c2b12 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sun, 30 Nov 2025 18:22:10 +0100 Subject: [PATCH 3/3] Update check64bit.cpp --- lib/check64bit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/check64bit.cpp b/lib/check64bit.cpp index f2eacf8cf44..eeda1c93648 100644 --- a/lib/check64bit.cpp +++ b/lib/check64bit.cpp @@ -45,7 +45,7 @@ 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->isIntegral() && vt->typeSize(settings->platform) == 4; + return vt && vt->pointer == 0 && vt->isIntegral() && vt->typeSize(settings->platform) == 4; } void Check64BitPortability::pointerassignment()