From aa454dda2eed4e71081bc57b1f32dfce2486b177 Mon Sep 17 00:00:00 2001 From: Balazs Benics Date: Thu, 1 Jul 2021 10:54:22 +0200 Subject: [PATCH] [analyzer] LValueToRValueBitCasts should evaluate to an r-value Previously `LValueToRValueBitCast`s were modeled in the same way how a regular `BitCast` was. However, this should not produce an l-value. Modeling bitcasts accurately is tricky, so it's probably better to model this expression by binding a fresh conjured value. The following code should not result in a diagnostic: ```lang=C++ __attribute__((always_inline)) static inline constexpr unsigned int_castf32_u32(float __A) { return __builtin_bit_cast(unsigned int, __A); // no-warning } ``` Previously, it reported `Address of stack memory associated with local variable '__A' returned to caller [core.StackAddressEscape]`. Differential Revision: https://reviews.llvm.org/D105017 Reviewed by: NoQ, vsavchenko --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 5 +++-- clang/test/Analysis/builtin_bitcast.cpp | 32 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 clang/test/Analysis/builtin_bitcast.cpp diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index a1c8128..bf3f8df 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -304,7 +304,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNodeSet dstPreStmt; getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this); - if (CastE->getCastKind() == CK_LValueToRValue) { + if (CastE->getCastKind() == CK_LValueToRValue || + CastE->getCastKind() == CK_LValueToRValueBitCast) { for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); I!=E; ++I) { ExplodedNode *subExprNode = *I; @@ -332,6 +333,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, switch (CastE->getCastKind()) { case CK_LValueToRValue: + case CK_LValueToRValueBitCast: llvm_unreachable("LValueToRValue casts handled earlier."); case CK_ToVoid: continue; @@ -380,7 +382,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_Dependent: case CK_ArrayToPointerDecay: case CK_BitCast: - case CK_LValueToRValueBitCast: case CK_AddressSpaceConversion: case CK_BooleanToSignedIntegral: case CK_IntegralToPointer: diff --git a/clang/test/Analysis/builtin_bitcast.cpp b/clang/test/Analysis/builtin_bitcast.cpp new file mode 100644 index 0000000..396e7ca --- /dev/null +++ b/clang/test/Analysis/builtin_bitcast.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_analyze_cc1 -triple x86_64-unknown-unknown -verify %s \ +// RUN: -analyzer-checker=core,debug.ExprInspection + +template void clang_analyzer_dump(T); + +__attribute__((always_inline)) static inline constexpr unsigned int _castf32_u32(float __A) { + return __builtin_bit_cast(unsigned int, __A); // no-warning +} + +void test(int i) { + _castf32_u32(42); + + float f = 42; + + // Loading from a floating point value results in unknown, + // which later materializes as a conjured value. + auto g = __builtin_bit_cast(unsigned int, f); + clang_analyzer_dump(g); + // expected-warning-re@-1 {{{{^conj_\$[0-9]+{unsigned int,}}}} + + auto g2 = __builtin_bit_cast(unsigned int, 42.0f); + clang_analyzer_dump(g2); + // expected-warning-re@-1 {{{{^conj_\$[0-9]+{unsigned int,}}}} + + auto g3 = __builtin_bit_cast(unsigned int, i); + clang_analyzer_dump(g3); + // expected-warning-re@-1 {{{{^reg_\$[0-9]+}}}} + + auto g4 = __builtin_bit_cast(unsigned long, &i); + clang_analyzer_dump(g4); + // expected-warning@-1 {{&i [as 64 bit integer]}} +} -- 2.7.4