Skip to content

Commit 4065ca6

Browse files
author
Vince Bridgers
committed
[analyzer] Correct SMT Layer for _BitInt cases refutations
Since _BitInt was added later, SMT did not comprehend getting a type by bitwidth that's not a power of 2. 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. ...  #9 <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&)
1 parent d659364 commit 4065ca6

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

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

Lines changed: 24 additions & 3 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,42 @@ 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+
QualType Ty = Ctx.getIntTypeForBitwidth(Int.getBitWidth(), Int.isSigned());
576+
// If Ty is Null, could be because the original type was a _BitInt.
577+
// Get the bit size and round up to next power of 2, max char size
578+
if (Ty.isNull()) {
579+
unsigned CharTypeSize = Ctx.getTypeSize(Ctx.CharTy);
580+
unsigned pow2DestWidth =
581+
std::max(llvm::bit_ceil(Int.getBitWidth()), CharTypeSize);
582+
Ty = Ctx.getIntTypeForBitwidth(pow2DestWidth, Int.isSigned());
583+
}
584+
return Ty;
585+
}
586+
587+
static inline bool IsPower2(unsigned bits) {
588+
return bits > 0 && (bits & (bits - 1)) == 0;
574589
}
575590

576591
// Get the QualTy for the input APSInt, and fix it if it has a bitwidth of 1.
577592
static inline std::pair<llvm::APSInt, QualType>
578593
fixAPSInt(ASTContext &Ctx, const llvm::APSInt &Int) {
579594
llvm::APSInt NewInt;
595+
unsigned APSIntBitwidth = Int.getBitWidth();
596+
QualType Ty = getAPSIntType(Ctx, Int);
580597

581598
// FIXME: This should be a cast from a 1-bit integer type to a boolean type,
582599
// but the former is not available in Clang. Instead, extend the APSInt
583600
// directly.
584-
if (Int.getBitWidth() == 1 && getAPSIntType(Ctx, Int).isNull()) {
601+
if (APSIntBitwidth == 1 && Ty.isNull()) {
585602
NewInt = Int.extend(Ctx.getTypeSize(Ctx.BoolTy));
603+
Ty = getAPSIntType(Ctx, NewInt);
604+
} else if (!IsPower2(APSIntBitwidth) && !getAPSIntType(Ctx, Int).isNull()) {
605+
Ty = getAPSIntType(Ctx, Int);
606+
NewInt = Int.extend(Ctx.getTypeSize(Ty));
586607
} else
587608
NewInt = Int;
588609

589-
return std::make_pair(NewInt, getAPSIntType(Ctx, NewInt));
610+
return std::make_pair(NewInt, Ty);
590611
}
591612

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

clang/test/Analysis/bitint-z3.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %clang_cc1 -analyze -analyzer-checker=core -w -DNO_CROSSCHECK -verify %s
2+
// RUN: %clang_cc1 -analyze -analyzer-checker=core -w -analyzer-config crosscheck-with-z3=true -verify %s
3+
// REQUIRES: z3
4+
5+
// The SMTConv layer did not comprehend _BitInt types (because this was an
6+
// evolved feature) and was crashing due to needed updates in 2 places.
7+
// Analysis is expected to find these cases using _BitInt without crashing.
8+
9+
_BitInt(35) a;
10+
int b;
11+
void c() {
12+
int d;
13+
if (a)
14+
b = d; // expected-warning{{Assigned value is uninitialized [core.uninitialized.Assign]}}
15+
}
16+
17+
int *d;
18+
_BitInt(3) e;
19+
void f() {
20+
int g;
21+
d = &g;
22+
e ?: 0; // expected-warning{{Address of stack memory associated with local variable 'g' is still referred to by the global variable 'd' upon returning to the caller. This will be a dangling reference [core.StackAddressEscape]}}
23+
}

0 commit comments

Comments
 (0)