baloghadamsoftware updated this revision to Diff 106626.
baloghadamsoftware added a comment.
Difference of unsigned is converted to signed.
https://reviews.llvm.org/D35109
Files:
include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
test/Analysis/std-c-library-functions.c
test/Analysis/svalbuilder-rearrange-comparisons.c
Index: test/Analysis/svalbuilder-rearrange-comparisons.c
===================================================================
--- /dev/null
+++ test/Analysis/svalbuilder-rearrange-comparisons.c
@@ -0,0 +1,156 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -verify %s
+
+void clang_analyzer_dump(int x);
+void clang_analyzer_printState();
+
+int f();
+
+void compare_different_symbol() {
+ int x = f(), y = f();
+ clang_analyzer_dump(x); // expected-warning{{conj_$2{int}}}
+ clang_analyzer_dump(y); // expected-warning{{conj_$5{int}}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{((conj_$2{int}) - (conj_$5{int})) == 0}}
+}
+
+void compare_different_symbol_plus_left_int() {
+ int x = f()+1, y = f();
+ clang_analyzer_dump(x); // expected-warning{{(conj_$2{int}) + 1}}
+ clang_analyzer_dump(y); // expected-warning{{conj_$5{int}}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{((conj_$5{int}) - (conj_$2{int})) == 1}}
+}
+
+void compare_different_symbol_minus_left_int() {
+ int x = f()-1, y = f();
+ clang_analyzer_dump(x); // expected-warning{{(conj_$2{int}) - 1}}
+ clang_analyzer_dump(y); // expected-warning{{conj_$5{int}}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{((conj_$2{int}) - (conj_$5{int})) == 1}}
+}
+
+void compare_different_symbol_plus_right_int() {
+ int x = f(), y = f()+2;
+ clang_analyzer_dump(x); // expected-warning{{conj_$2{int}}}
+ clang_analyzer_dump(y); // expected-warning{{(conj_$5{int}) + 2}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{((conj_$2{int}) - (conj_$5{int})) == 2}}
+}
+
+void compare_different_symbol_minus_right_int() {
+ int x = f(), y = f()-2;
+ clang_analyzer_dump(x); // expected-warning{{conj_$2{int}}}
+ clang_analyzer_dump(y); // expected-warning{{(conj_$5{int}) - 2}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{((conj_$5{int}) - (conj_$2{int})) == 2}}
+}
+
+void compare_different_symbol_plus_left_plus_right_int() {
+ int x = f()+2, y = f()+1;
+ clang_analyzer_dump(x); // expected-warning{{(conj_$2{int}) + 2}}
+ clang_analyzer_dump(y); // expected-warning{{(conj_$5{int}) + 1}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{((conj_$5{int}) - (conj_$2{int})) == 1}}
+}
+
+void compare_different_symbol_plus_left_minus_right_int() {
+ int x = f()+2, y = f()-1;
+ clang_analyzer_dump(x); // expected-warning{{(conj_$2{int}) + 2}}
+ clang_analyzer_dump(y); // expected-warning{{(conj_$5{int}) - 1}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{((conj_$5{int}) - (conj_$2{int})) == 3}}
+}
+
+void compare_different_symbol_minus_left_plus_right_int() {
+ int x = f()-2, y = f()+1;
+ clang_analyzer_dump(x); // expected-warning{{(conj_$2{int}) - 2}}
+ clang_analyzer_dump(y); // expected-warning{{(conj_$5{int}) + 1}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{((conj_$2{int}) - (conj_$5{int})) == 3}}
+}
+
+void compare_different_symbol_minus_left_minus_right_int() {
+ int x = f()-2, y = f()-1;
+ clang_analyzer_dump(x); // expected-warning{{(conj_$2{int}) - 2}}
+ clang_analyzer_dump(y); // expected-warning{{(conj_$5{int}) - 1}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{((conj_$2{int}) - (conj_$5{int})) == 1}}
+}
+
+void compare_same_symbol() {
+ int x = f(), y = x;
+ clang_analyzer_dump(x); // expected-warning{{conj_$2{int}}}
+ clang_analyzer_dump(y); // expected-warning{{conj_$2{int}}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{1 S32b}}
+}
+
+void compare_same_symbol_plus_left_int() {
+ int x = f(), y = x;
+ ++x;
+ clang_analyzer_dump(x); // expected-warning{{(conj_$2{int}) + 1}}
+ clang_analyzer_dump(y); // expected-warning{{conj_$2{int}}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{0 S32b}}
+}
+
+void compare_same_symbol_minus_left_int() {
+ int x = f(), y = x;
+ --x;
+ clang_analyzer_dump(x); // expected-warning{{(conj_$2{int}) - 1}}
+ clang_analyzer_dump(y); // expected-warning{{conj_$2{int}}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{0 S32b}}
+}
+
+void compare_same_symbol_plus_right_int() {
+ int x = f(), y = x+1;
+ clang_analyzer_dump(x); // expected-warning{{conj_$2{int}}}
+ clang_analyzer_dump(y); // expected-warning{{(conj_$2{int}) + 1}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{0 S32b}}
+}
+
+void compare_same_symbol_minus_right_int() {
+ int x = f(), y = x-1;
+ clang_analyzer_dump(x); // expected-warning{{conj_$2{int}}}
+ clang_analyzer_dump(y); // expected-warning{{(conj_$2{int}) - 1}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{0 S32b}}
+}
+
+void compare_same_symbol_plus_left_plus_right_int() {
+ int x = f(), y = x+1;
+ ++x;
+ clang_analyzer_dump(x); // expected-warning{{(conj_$2{int}) + 1}}
+ clang_analyzer_dump(y); // expected-warning{{(conj_$2{int}) + 1}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{1 S32b}}
+}
+
+void compare_same_symbol_plus_left_minus_right_int() {
+ int x = f(), y = x-1;
+ ++x;
+ clang_analyzer_dump(x); // expected-warning{{(conj_$2{int}) + 1}}
+ clang_analyzer_dump(y); // expected-warning{{(conj_$2{int}) - 1}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{0 S32b}}
+}
+
+void compare_same_symbol_minus_left_plus_right_int() {
+ int x = f(), y = x+1;
+ --x;
+ clang_analyzer_dump(x); // expected-warning{{(conj_$2{int}) - 1}}
+ clang_analyzer_dump(y); // expected-warning{{(conj_$2{int}) + 1}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{0 S32b}}
+}
+
+void compare_same_symbol_minus_left_minus_right_int() {
+ int x = f(), y = x-1;
+ --x;
+ clang_analyzer_dump(x); // expected-warning{{(conj_$2{int}) - 1}}
+ clang_analyzer_dump(y); // expected-warning{{(conj_$2{int}) - 1}}
+ clang_analyzer_dump(x == y);
+ // expected-warning@-1{{1 S32b}}
+}
Index: test/Analysis/std-c-library-functions.c
===================================================================
--- test/Analysis/std-c-library-functions.c
+++ test/Analysis/std-c-library-functions.c
@@ -57,8 +57,7 @@
size_t y = fread(buf, sizeof(int), 10, fp);
clang_analyzer_eval(y <= 10); // expected-warning{{TRUE}}
size_t z = fwrite(buf, sizeof(int), y, fp);
- // FIXME: should be TRUE once symbol-symbol constraint support is improved.
- clang_analyzer_eval(z <= y); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(z <= y); // expected-warning{{TRUE}}
}
ssize_t getline(char **, size_t *, FILE *);
Index: lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
===================================================================
--- lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -554,6 +554,82 @@
if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs))
return MakeSymIntVal(Sym, op, *RHSValue, resultTy);
+ // If comparing two symbolic expressions of the format S, S+n or S-n
+ // rearrange the comparison by moving symbols to the left side and the
+ // concrete integer to the right. This enables the range based constraint
+ // manager to handle these comparisons.
+ if (BinaryOperator::isComparisonOp(op) &&
+ rhs.getSubKind() == nonloc::SymbolValKind) {
+ SymbolRef rSym = rhs.castAs<nonloc::SymbolVal>().getSymbol();
+ if (Sym->getType() == rSym->getType()) {
+ QualType T = Sym->getType();
+ if (T->isUnsignedIntegerOrEnumerationType ()) {
+ T = Context.getCorrespondingSignedType(T);
+ }
+
+ const llvm::APSInt *lInt = nullptr, *rInt = nullptr;
+ BinaryOperator::Opcode lop, rop;
+
+ if (const SymIntExpr *lSymIntExpr = dyn_cast<SymIntExpr>(Sym)) {
+ lop = lSymIntExpr->getOpcode();
+ if (BinaryOperator::isAdditiveOp(lop)) {
+ lInt = &BasicVals.Convert(T, lSymIntExpr->getRHS());
+ Sym = lSymIntExpr->getLHS();
+ }
+ }
+ if (const SymIntExpr *rSymIntExpr = dyn_cast<SymIntExpr>(rSym)) {
+ rop = rSymIntExpr->getOpcode();
+ if (BinaryOperator::isAdditiveOp(rop)) {
+ rInt = &BasicVals.Convert(T, rSymIntExpr->getRHS());
+ rSym = rSymIntExpr->getLHS();
+ }
+ }
+
+ bool reverse; // Avoid negative numbers in case of unsigned types
+ const llvm::APSInt *newRhs;
+ if (lInt && rInt) {
+ if (lop != rop) {
+ newRhs = BasicVals.evalAPSInt(BO_Add, *lInt, *rInt);
+ reverse = (lop == BO_Add);
+ } else {
+ if (*lInt >= *rInt) {
+ newRhs = BasicVals.evalAPSInt(BO_Sub, *lInt, *rInt);
+ reverse = (lop == BO_Add);
+ } else {
+ newRhs = BasicVals.evalAPSInt(BO_Sub, *rInt, *lInt);
+ reverse = (lop == BO_Sub);
+ }
+ }
+ } else if (lInt) {
+ newRhs = lInt;
+ reverse = (lop == BO_Add);
+ } else if (rInt) {
+ newRhs = rInt;
+ reverse = (rop == BO_Sub);
+ } else {
+ newRhs = &BasicVals.getValue(0, T);
+ reverse = false;
+ }
+
+ // If the two symbols are equal, compare only the integers and return
+ // the concrete result. If they are different, return the rearranged
+ // expression.
+ if (Sym == rSym) {
+ return nonloc::ConcreteInt(*BasicVals.evalAPSInt(
+ op, BasicVals.getValue(0, T), *newRhs));
+ } else {
+ if (reverse) {
+ op = BinaryOperator::reverseComparisonOp(op);
+ }
+ const SymExpr *newLhs =
+ reverse
+ ? SymMgr.getSymSymExpr(rSym, BO_Sub, Sym, T)
+ : SymMgr.getSymSymExpr(Sym, BO_Sub, rSym, T);
+ return makeNonLoc(newLhs, op, *newRhs, resultTy);
+ }
+ }
+ }
+
// Give up -- this is not a symbolic expression we can handle.
return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy);
}
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -8496,6 +8496,39 @@
}
}
+QualType ASTContext::getCorrespondingSignedType(QualType T) const {
+ assert(T->hasUnsignedIntegerRepresentation() && "Unexpected type");
+
+ // Turn <4 x signed int> -> <4 x unsigned int>
+ if (const VectorType *VTy = T->getAs<VectorType>())
+ return getVectorType(getCorrespondingSignedType(VTy->getElementType()),
+ VTy->getNumElements(), VTy->getVectorKind());
+
+ // For enums, we return the unsigned version of the base type.
+ if (const EnumType *ETy = T->getAs<EnumType>())
+ T = ETy->getDecl()->getIntegerType();
+
+ const BuiltinType *BTy = T->getAs<BuiltinType>();
+ assert(BTy && "Unexpected unsigned integer type");
+ switch (BTy->getKind()) {
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ return SignedCharTy;
+ case BuiltinType::UShort:
+ return ShortTy;
+ case BuiltinType::UInt:
+ return IntTy;
+ case BuiltinType::ULong:
+ return LongTy;
+ case BuiltinType::ULongLong:
+ return LongLongTy;
+ case BuiltinType::UInt128:
+ return Int128Ty;
+ default:
+ llvm_unreachable("Unexpected unsigned integer type");
+ }
+}
+
ASTMutationListener::~ASTMutationListener() { }
void ASTMutationListener::DeducedReturnType(const FunctionDecl *FD,
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -2409,6 +2409,9 @@
// corresponding unsigned integer type.
QualType getCorrespondingUnsignedType(QualType T) const;
+ // The reverse of the previous function.
+ QualType getCorrespondingSignedType(QualType T) const;
+
//===--------------------------------------------------------------------===//
// Integer Values
//===--------------------------------------------------------------------===//
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits