mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 22:00:10 +00:00
[analyzer] Produce SymbolCast symbols for integral types in SValBuilder::evalCast
Summary: Produce SymbolCast for integral types in `evalCast` function. Apply several simplification techniques while producing the symbols. Added a boolean option `handle-integral-cast-for-ranges` under `-analyzer-config` flag. Disabled the feature by default. Differential Revision: https://reviews.llvm.org/D105340
This commit is contained in:
parent
7f4d66f23e
commit
d835dd4cf5
@ -320,6 +320,11 @@ ANALYZER_OPTION(bool, ShouldDisplayCheckerNameForText, "display-checker-name",
|
||||
"Display the checker name for textual outputs",
|
||||
true)
|
||||
|
||||
ANALYZER_OPTION(bool, ShouldSupportSymbolicIntegerCasts,
|
||||
"support-symbolic-integer-casts",
|
||||
"Produce cast symbols for integral types.",
|
||||
false)
|
||||
|
||||
ANALYZER_OPTION(
|
||||
bool, ShouldConsiderSingleElementArraysAsFlexibleArrayMembers,
|
||||
"consider-single-element-arrays-as-flexible-array-members",
|
||||
|
@ -96,6 +96,17 @@ protected:
|
||||
QualType OriginalTy);
|
||||
SVal evalCastSubKind(nonloc::PointerToMember V, QualType CastTy,
|
||||
QualType OriginalTy);
|
||||
/// Reduce cast expression by removing redundant intermediate casts.
|
||||
/// E.g.
|
||||
/// - (char)(short)(int x) -> (char)(int x)
|
||||
/// - (int)(int x) -> int x
|
||||
///
|
||||
/// \param V -- SymbolVal, which pressumably contains SymbolCast or any symbol
|
||||
/// that is applicable for cast operation.
|
||||
/// \param CastTy -- QualType, which `V` shall be cast to.
|
||||
/// \return SVal with simplified cast expression.
|
||||
/// \note: Currently only support integral casts.
|
||||
SVal simplifySymbolCast(nonloc::SymbolVal V, QualType CastTy);
|
||||
|
||||
public:
|
||||
SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
|
||||
@ -103,18 +114,6 @@ public:
|
||||
|
||||
virtual ~SValBuilder() = default;
|
||||
|
||||
bool haveSameType(const SymExpr *Sym1, const SymExpr *Sym2) {
|
||||
return haveSameType(Sym1->getType(), Sym2->getType());
|
||||
}
|
||||
|
||||
bool haveSameType(QualType Ty1, QualType Ty2) {
|
||||
// FIXME: Remove the second disjunct when we support symbolic
|
||||
// truncation/extension.
|
||||
return (Context.getCanonicalType(Ty1) == Context.getCanonicalType(Ty2) ||
|
||||
(Ty1->isIntegralOrEnumerationType() &&
|
||||
Ty2->isIntegralOrEnumerationType()));
|
||||
}
|
||||
|
||||
SVal evalCast(SVal V, QualType CastTy, QualType OriginalTy);
|
||||
|
||||
// Handles casts of type CK_IntegralCast.
|
||||
|
@ -416,7 +416,10 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
||||
case CK_IntegralCast: {
|
||||
// Delegate to SValBuilder to process.
|
||||
SVal V = state->getSVal(Ex, LCtx);
|
||||
V = svalBuilder.evalIntegralCast(state, V, T, ExTy);
|
||||
if (AMgr.options.ShouldSupportSymbolicIntegerCasts)
|
||||
V = svalBuilder.evalCast(V, T, ExTy);
|
||||
else
|
||||
V = svalBuilder.evalIntegralCast(state, V, T, ExTy);
|
||||
state = state->BindExpr(CastE, LCtx, V);
|
||||
Bldr.generateNode(CastE, Pred, state);
|
||||
continue;
|
||||
|
@ -980,15 +980,19 @@ SVal SValBuilder::evalCastSubKind(nonloc::SymbolVal V, QualType CastTy,
|
||||
} else {
|
||||
// Symbol to integer, float.
|
||||
QualType T = Context.getCanonicalType(SE->getType());
|
||||
// If types are the same or both are integers, ignore the cast.
|
||||
// FIXME: Remove this hack when we support symbolic truncation/extension.
|
||||
// HACK: If both castTy and T are integers, ignore the cast. This is
|
||||
// not a permanent solution. Eventually we want to precisely handle
|
||||
// extension/truncation of symbolic integers. This prevents us from losing
|
||||
// precision when we assign 'x = y' and 'y' is symbolic and x and y are
|
||||
// different integer types.
|
||||
if (haveSameType(T, CastTy))
|
||||
return V;
|
||||
|
||||
// Produce SymbolCast if CastTy and T are different integers.
|
||||
// NOTE: In the end the type of SymbolCast shall be equal to CastTy.
|
||||
if (T->isIntegralOrEnumerationType() &&
|
||||
CastTy->isIntegralOrEnumerationType()) {
|
||||
AnalyzerOptions &Opts =
|
||||
StateMgr.getOwningEngine().getAnalysisManager().getAnalyzerOptions();
|
||||
// If appropriate option is disabled, ignore the cast.
|
||||
// NOTE: ShouldSupportSymbolicIntegerCasts is `false` by default.
|
||||
if (!Opts.ShouldSupportSymbolicIntegerCasts)
|
||||
return V;
|
||||
return simplifySymbolCast(V, CastTy);
|
||||
}
|
||||
if (!Loc::isLocType(CastTy))
|
||||
if (!IsUnknownOriginalType || !CastTy->isFloatingType() ||
|
||||
T->isFloatingType())
|
||||
@ -1004,3 +1008,75 @@ SVal SValBuilder::evalCastSubKind(nonloc::PointerToMember V, QualType CastTy,
|
||||
// Member pointer to whatever.
|
||||
return V;
|
||||
}
|
||||
|
||||
SVal clang::ento::SValBuilder::simplifySymbolCast(nonloc::SymbolVal V,
|
||||
QualType CastTy) {
|
||||
// We use seven conditions to recognize a simplification case.
|
||||
// For the clarity let `CastTy` be `C`, SE->getType() - `T`, root type - `R`,
|
||||
// prefix `u` for unsigned, `s` for signed, no prefix - any sign:
|
||||
// E.g. (char)(short)(uint x)
|
||||
// ( sC )( sT )( uR x)
|
||||
//
|
||||
// C === R (the same type)
|
||||
// (char)(char x) -> (char x)
|
||||
// (long)(long x) -> (long x)
|
||||
// Note: Comparisons operators below are for bit width.
|
||||
// C == T
|
||||
// (short)(short)(int x) -> (short)(int x)
|
||||
// (int)(long)(char x) -> (int)(char x) (sizeof(long) == sizeof(int))
|
||||
// (long)(ullong)(char x) -> (long)(char x) (sizeof(long) == sizeof(ullong))
|
||||
// C < T
|
||||
// (short)(int)(char x) -> (short)(char x)
|
||||
// (char)(int)(short x) -> (char)(short x)
|
||||
// (short)(int)(short x) -> (short x)
|
||||
// C > T > uR
|
||||
// (int)(short)(uchar x) -> (int)(uchar x)
|
||||
// (uint)(short)(uchar x) -> (uint)(uchar x)
|
||||
// (int)(ushort)(uchar x) -> (int)(uchar x)
|
||||
// C > sT > sR
|
||||
// (int)(short)(char x) -> (int)(char x)
|
||||
// (uint)(short)(char x) -> (uint)(char x)
|
||||
// C > sT == sR
|
||||
// (int)(char)(char x) -> (int)(char x)
|
||||
// (uint)(short)(short x) -> (uint)(short x)
|
||||
// C > uT == uR
|
||||
// (int)(uchar)(uchar x) -> (int)(uchar x)
|
||||
// (uint)(ushort)(ushort x) -> (uint)(ushort x)
|
||||
// (llong)(ulong)(uint x) -> (llong)(uint x) (sizeof(ulong) == sizeof(uint))
|
||||
|
||||
SymbolRef SE = V.getSymbol();
|
||||
QualType T = Context.getCanonicalType(SE->getType());
|
||||
|
||||
if (T == CastTy)
|
||||
return V;
|
||||
|
||||
if (!isa<SymbolCast>(SE))
|
||||
return makeNonLoc(SE, T, CastTy);
|
||||
|
||||
SymbolRef RootSym = cast<SymbolCast>(SE)->getOperand();
|
||||
QualType RT = RootSym->getType().getCanonicalType();
|
||||
|
||||
BasicValueFactory &BVF = getBasicValueFactory();
|
||||
APSIntType CTy = BVF.getAPSIntType(CastTy);
|
||||
APSIntType TTy = BVF.getAPSIntType(T);
|
||||
|
||||
const auto WC = CTy.getBitWidth();
|
||||
const auto WT = TTy.getBitWidth();
|
||||
|
||||
if (WC <= WT) {
|
||||
const bool isSameType = (RT == CastTy);
|
||||
if (isSameType)
|
||||
return nonloc::SymbolVal(RootSym);
|
||||
return makeNonLoc(RootSym, RT, CastTy);
|
||||
}
|
||||
|
||||
APSIntType RTy = BVF.getAPSIntType(RT);
|
||||
const auto WR = RTy.getBitWidth();
|
||||
const bool UT = TTy.isUnsigned();
|
||||
const bool UR = RTy.isUnsigned();
|
||||
|
||||
if (((WT > WR) && (UR || !UT)) || ((WT == WR) && (UT == UR)))
|
||||
return makeNonLoc(RootSym, RT, CastTy);
|
||||
|
||||
return makeNonLoc(SE, T, CastTy);
|
||||
}
|
||||
|
@ -115,6 +115,7 @@
|
||||
// CHECK-NEXT: serialize-stats = false
|
||||
// CHECK-NEXT: silence-checkers = ""
|
||||
// CHECK-NEXT: stable-report-filename = false
|
||||
// CHECK-NEXT: support-symbolic-integer-casts = false
|
||||
// CHECK-NEXT: suppress-c++-stdlib = true
|
||||
// CHECK-NEXT: suppress-inlined-defensive-checks = true
|
||||
// CHECK-NEXT: suppress-null-return-paths = true
|
||||
|
1640
clang/test/Analysis/produce-symbolcast_x64.cpp
Normal file
1640
clang/test/Analysis/produce-symbolcast_x64.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1640
clang/test/Analysis/produce-symbolcast_x86.cpp
Normal file
1640
clang/test/Analysis/produce-symbolcast_x86.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user