Charusso created this revision.
Charusso added a reviewer: NoQ.
Charusso added a project: clang.
Herald added subscribers: cfe-commits, dkrupp, donat.nagy, Szelethus, 
mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.

We do not support evaluating bitwise operations, so that when we check for
their results being null previously we did a state-split because it is a
fresh new symbol and it could be null and non-null as well. The problem was
the left-hand side operand of the operation already has constraint range
informations which could contradicts with the current new assumption.
>From now we apply the constraint range informations of the left-hand side
operand in order to prevent false assumptions.


Repository:
  rC Clang

https://reviews.llvm.org/D65239

Files:
  clang/include/clang/AST/Expr.h
  
clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/bitwise-nullability.cpp

Index: clang/test/Analysis/bitwise-nullability.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/bitwise-nullability.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+
+// expected-no-diagnostics:
+// We do not support evaluating bitwise operations, so that when we check for
+// their results being null previously we did a state-split because it is a
+// fresh new symbol and it could be null and non-null as well. The problem was
+// the left-hand side operand of the operation already has constraint range
+// informations which could contradicts with the current new assumption.
+// From now we apply the constraint range informations of the left-hand side
+// operand in order to prevent false assumptions.
+
+typedef unsigned long long uint64_t;
+
+void test_narrowing_down_range(uint64_t Magic) {
+  uint64_t MaskedMagic = Magic & (0xffffffffffffffffULL >> 13);
+
+  if (Magic) {
+    // no-warning: 'Assuming 'Magic' is 0' was here.
+    return;
+  }
+
+  if (MaskedMagic) {
+    // no-warning: 'Assuming 'MaskedMagic' is not equal to 0' was here.
+    (void)(1 / Magic);
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -443,16 +443,17 @@
 /// Apply implicit constraints for bitwise OR- and AND-.
 /// For unsigned types, bitwise OR with a constant always returns
 /// a value greater-or-equal than the constant, and bitwise AND
-/// returns a value less-or-equal then the constant.
+/// returns a value less-or-equal than the constant.
+/// Also apply the previously applied constraint range information of the
+/// left-hand side operand of \p SIE in order to prevent false assumptions.
 ///
-/// Pattern matches the expression \p Sym against those rule,
+/// Pattern matches the expression \p SIE against those rules,
 /// and applies the required constraints.
-/// \p Input Previously established expression range set
-static RangeSet applyBitwiseConstraints(
-    BasicValueFactory &BV,
-    RangeSet::Factory &F,
-    RangeSet Input,
-    const SymIntExpr* SIE) {
+/// \p Result Previously established expression range set
+static RangeSet applyBitwiseConstraints(ProgramStateRef State,
+                                        BasicValueFactory &BV,
+                                        RangeSet::Factory &F, RangeSet Result,
+                                        const SymIntExpr *SIE) {
   QualType T = SIE->getType();
   bool IsUnsigned = T->isUnsignedIntegerType();
   const llvm::APSInt &RHS = SIE->getRHS();
@@ -461,19 +462,34 @@
 
   // For unsigned types, the output of bitwise-or is bigger-or-equal than RHS.
   if (Operator == BO_Or && IsUnsigned)
-    return Input.Intersect(BV, F, RHS, BV.getMaxValue(T));
+    return Result.Intersect(BV, F, RHS, BV.getMaxValue(T));
 
   // Bitwise-or with a non-zero constant is always non-zero.
   if (Operator == BO_Or && RHS != Zero)
-    return assumeNonZero(BV, F, SIE, Input);
+    return assumeNonZero(BV, F, SIE, Result);
 
   // For unsigned types, or positive RHS,
   // bitwise-and output is always smaller-or-equal than RHS (assuming two's
   // complement representation of signed types).
   if (Operator == BO_And && (IsUnsigned || RHS >= Zero))
-    return Input.Intersect(BV, F, BV.getMinValue(T), RHS);
+    Result = Result.Intersect(BV, F, BV.getMinValue(T), RHS);
+
+  // For all of the bitwise operations,
+  // if they remain in that 'SymIntExpr' form that means we cannot evaluate the
+  // operation properly and they remain range-based. At this point we would
+  // introduce a completely new 'RangeSet' with new assumptions and we would
+  // forget about the previous constraint range information of the left-hand
+  // side operand of 'SIE'. Here we apply the previously applied range to the
+  // current range by intersecting them to prevent false assumptions.
+  ConstraintRangeTy Constraints = State->get<ConstraintRange>();
+  if (const RangeSet *PreviousRS = Constraints.lookup(SIE->getLHS())) {
+    if (!PreviousRS->isEmpty()) {
+      RangeSet::iterator I = PreviousRS->begin();
+      Result = Result.Intersect(BV, F, I->From(), I->To());
+    }
+  }
 
-  return Input;
+  return Result;
 }
 
 RangeSet RangeConstraintManager::getRange(ProgramStateRef State,
@@ -506,8 +522,9 @@
     return assumeNonZero(BV, F, Sym, Result);
 
   // Known constraints on ranges of bitwise expressions.
-  if (const SymIntExpr* SIE = dyn_cast<SymIntExpr>(Sym))
-    return applyBitwiseConstraints(BV, F, Result, SIE);
+  if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(Sym))
+    if (BinaryOperator::isBitwiseOrShiftOp(SIE->getOpcode()))
+      return applyBitwiseConstraints(State, BV, F, Result, SIE);
 
   return Result;
 }
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -117,6 +117,7 @@
                      const RangeSet &Other) const;
   RangeSet Negate(BasicValueFactory &BV, Factory &F) const;
 
+  void print() const { print(llvm::errs()); }
   void print(raw_ostream &os) const;
 
   bool operator==(const RangeSet &other) const {
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -3486,6 +3486,11 @@
   static bool isBitwiseOp(Opcode Opc) { return Opc >= BO_And && Opc <= BO_Or; }
   bool isBitwiseOp() const { return isBitwiseOp(getOpcode()); }
 
+  static bool isBitwiseOrShiftOp(Opcode Opc) {
+    return isBitwiseOp(Opc) || isShiftOp(Opc);
+  }
+  bool isBitwiseOrShiftOp() const { return isBitwiseOrShiftOp(getOpcode()); }
+
   static bool isRelationalOp(Opcode Opc) { return Opc >= BO_LT && Opc<=BO_GE; }
   bool isRelationalOp() const { return isRelationalOp(getOpcode()); }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to