Skip to content

Commit ec8d68b

Browse files
vabridgersVince Bridgers
andauthored
[clang][analyzer] Correct SMT Layer for _BitInt cases refutations (#143310)
Since _BitInt was added later, ASTContext did not comprehend getting a type by bitwidth that's not a power of 2, and the SMT layer also did not comprehend this. This led to unexpected crashes using Z3 refutation during randomized testing. The assertion and redacted and summarized crash stack is shown here. clang: ../../clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h:103: static llvm::SMTExprRef clang::ento::SMTConv::fromBinOp(llvm::SMTSolverRef &, const llvm::SMTExprRef &, const BinaryOperator::Opcode, const llvm::SMTExprRef &, bool): Assertion `*Solver->getSort(LHS) == *Solver->getSort(RHS) && "AST's must have the same sort!"' failed. ... <address> clang::ento::SMTConv::fromBinOp(std::shared_ptr<llvm::SMTSolver>&, llvm::SMTExpr const* const&, clang::BinaryOperatorKind, llvm::SMTExpr const* const&, bool) SMTConstraintManager.cpp clang::ASTContext&, llvm::SMTExpr const* const&, clang::QualType, clang::BinaryOperatorKind, llvm::SMTExpr const* const&, clang::QualType, clang::QualType*) SMTConstraintManager.cpp clang::ASTContext&, clang::ento::SymExpr const*, llvm::APSInt const&, llvm::APSInt const&, bool) SMTConstraintManager.cpp clang::ento::ExplodedNode const*, clang::ento::PathSensitiveBugReport&) --------- Co-authored-by: Vince Bridgers <[email protected]>
1 parent 8e4f0d8 commit ec8d68b

File tree

2 files changed

+43
-7
lines changed

2 files changed

+43
-7
lines changed

clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
1919
#include "llvm/Support/SMTAPI.h"
2020

21+
#include <algorithm>
22+
2123
namespace clang {
2224
namespace ento {
2325

@@ -570,23 +572,35 @@ class SMTConv {
570572
// TODO: Refactor to put elsewhere
571573
static inline QualType getAPSIntType(ASTContext &Ctx,
572574
const llvm::APSInt &Int) {
573-
return Ctx.getIntTypeForBitwidth(Int.getBitWidth(), Int.isSigned());
575+
const QualType Ty =
576+
Ctx.getIntTypeForBitwidth(Int.getBitWidth(), Int.isSigned());
577+
if (!Ty.isNull())
578+
return Ty;
579+
// If Ty is Null, could be because the original type was a _BitInt.
580+
// Get the size of the _BitInt type (expressed in bits) and round it up to
581+
// the next power of 2 that is at least the bit size of 'char' (usually 8).
582+
unsigned CharTypeSize = Ctx.getTypeSize(Ctx.CharTy);
583+
unsigned Pow2DestWidth =
584+
std::max(llvm::bit_ceil(Int.getBitWidth()), CharTypeSize);
585+
return Ctx.getIntTypeForBitwidth(Pow2DestWidth, Int.isSigned());
574586
}
575587

576588
// Get the QualTy for the input APSInt, and fix it if it has a bitwidth of 1.
577589
static inline std::pair<llvm::APSInt, QualType>
578590
fixAPSInt(ASTContext &Ctx, const llvm::APSInt &Int) {
579591
llvm::APSInt NewInt;
592+
unsigned APSIntBitwidth = Int.getBitWidth();
593+
QualType Ty = getAPSIntType(Ctx, Int);
580594

581595
// FIXME: This should be a cast from a 1-bit integer type to a boolean type,
582596
// but the former is not available in Clang. Instead, extend the APSInt
583597
// directly.
584-
if (Int.getBitWidth() == 1 && getAPSIntType(Ctx, Int).isNull()) {
585-
NewInt = Int.extend(Ctx.getTypeSize(Ctx.BoolTy));
586-
} else
587-
NewInt = Int;
588-
589-
return std::make_pair(NewInt, getAPSIntType(Ctx, NewInt));
598+
if (APSIntBitwidth == 1 && Ty.isNull())
599+
return {Int.extend(Ctx.getTypeSize(Ctx.BoolTy)),
600+
getAPSIntType(Ctx, NewInt)};
601+
if (llvm::isPowerOf2_32(APSIntBitwidth) || Ty.isNull())
602+
return {Int, Ty};
603+
return {Int.extend(Ctx.getTypeSize(Ty)), Ty};
590604
}
591605

592606
// Perform implicit type conversion on binary symbolic expressions.

clang/test/Analysis/bitint-z3.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -w \
2+
// RUN: -analyzer-config crosscheck-with-z3=true -verify %s
3+
// REQUIRES: z3
4+
5+
// Previously these tests were crashing because the SMTConv layer did not
6+
// comprehend the _BitInt types.
7+
8+
void clang_analyzer_warnIfReached();
9+
10+
void c(int b, _BitInt(35) a) {
11+
int d = 0;
12+
if (a)
13+
b = d;
14+
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
15+
}
16+
17+
void f(int *d, _BitInt(3) e) {
18+
int g;
19+
d = &g;
20+
e ?: 0;
21+
clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
22+
}

0 commit comments

Comments
 (0)