Skip to content

Commit c8d5733

Browse files
Tomasz Kamińskitstellar
authored andcommitted
[analyzer] Fix assertion failure in SMT conversion for unary operator on floats
In the handling of the Symbols from the RangExpr, the code assumed that the operands of the unary operators need to have integral type. However, the CSA can create SymExpr with a floating point operand, when the integer value is cast into it, like `(float)h == (float)l` where both of `h` and `l` are integers. This patch handles such situations, by using `fromFloatUnOp()` instead of `fromUnOp()`, when the operand have a floating point type. I have investigated all other calls of `fromUnOp()`, and for one in: - `getZeroExpr()` is applied only on boolean types, so it correct - `fromBinOp()` is not invoked for floating points - `fromFloatUnOp()` I am uncertain about this case and I was not able to produce a test that would reach this point, as a negation of floating points numbers seem to produce `Unknown` symbols. This issue exists since the introduction of `UnarySymExpr` in D125318 and their handling for Z3 in D125547. Patch by Tomasz Kamiński. Reviewed By: mikhail.ramalho Differential Revision: https://reviews.llvm.org/D140891 (cherry picked from commit 3674421)
1 parent d6d97e8 commit c8d5733

File tree

2 files changed

+27
-3
lines changed

2 files changed

+27
-3
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,9 @@ class SMTConv {
454454
llvm::SMTExprRef OperandExp =
455455
getSymExpr(Solver, Ctx, USE->getOperand(), &OperandTy, hasComparison);
456456
llvm::SMTExprRef UnaryExp =
457-
fromUnOp(Solver, USE->getOpcode(), OperandExp);
457+
OperandTy->isRealFloatingType()
458+
? fromFloatUnOp(Solver, USE->getOpcode(), OperandExp)
459+
: fromUnOp(Solver, USE->getOpcode(), OperandExp);
458460

459461
// Currently, without the `support-symbolic-integer-casts=true` option,
460462
// we do not emit `SymbolCast`s for implicit casts.

clang/test/Analysis/z3-crosscheck.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -DNO_CROSSCHECK -verify %s
2-
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config crosscheck-with-z3=true -verify %s
1+
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -DNO_CROSSCHECK -verify %s
2+
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config crosscheck-with-z3=true -verify %s
33
// REQUIRES: z3
44

5+
void clang_analyzer_dump(float);
6+
57
int foo(int x)
68
{
79
int *z = 0;
@@ -55,3 +57,23 @@ void i() {
5557
h(2);
5658
}
5759
}
60+
61+
void floatUnaryNegInEq(int h, int l) {
62+
int j;
63+
clang_analyzer_dump(-(float)h); // expected-warning-re{{-(float) (reg_${{[0-9]+}}<int h>)}}
64+
clang_analyzer_dump((float)l); // expected-warning-re {{(float) (reg_${{[0-9]+}}<int l>)}}
65+
if (-(float)h != (float)l) { // should not crash
66+
j += 10;
67+
// expected-warning@-1{{garbage}}
68+
}
69+
}
70+
71+
void floatUnaryLNotInEq(int h, int l) {
72+
int j;
73+
clang_analyzer_dump(!(float)h); // expected-warning{{Unknown}}
74+
clang_analyzer_dump((float)l); // expected-warning-re {{(float) (reg_${{[0-9]+}}<int l>)}}
75+
if ((!(float)h) != (float)l) { // should not crash
76+
j += 10;
77+
// expected-warning@-1{{garbage}}
78+
}
79+
}

0 commit comments

Comments
 (0)