Charusso updated this revision to Diff 212440.
Charusso marked 6 inline comments as done.
Charusso added a comment.

- Fix.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D65239/new/

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
  clang/test/Analysis/bitwise-ranges.cpp

Index: clang/test/Analysis/bitwise-ranges.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/bitwise-ranges.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=core,debug.ExprInspection \
+// RUN:  -verify %s
+
+void clang_analyzer_eval(int);
+
+void test_range(unsigned int X) {
+  if (X < 2 || X > 3)
+    return;
+
+  clang_analyzer_eval(X >= 2 && X <= 3);
+  // expected-warning@-1 {{TRUE}}
+
+  // We have no non-null constraint range information available for 'A'.
+  unsigned int A = X | 8;
+  clang_analyzer_eval((A > 0 && A < 0) || A == 0);
+  // expected-warning@-1 {{FALSE}}
+
+  unsigned int B = X & 8;
+  clang_analyzer_eval((B >= 1 && B <= 8) || B == 0);
+  // expected-warning@-1 {{TRUE}}
+
+  unsigned int C = X & 1;
+  clang_analyzer_eval((C >= 1 && C <= 1) || C == 0);
+  // expected-warning@-1 {{TRUE}}
+
+  unsigned int D = X << 1;
+  clang_analyzer_eval((D >= 1 && D <= 4294967295) || D == 0);
+  // expected-warning@-1 {{TRUE}}
+
+  unsigned int E = X >> 1;
+  clang_analyzer_eval((E >= 1 && E <= 4294967295) || E == 0);
+  // expected-warning@-1 {{TRUE}}
+
+  void(X / 0);
+  // expected-warning@-1 {{division by zero is undefined}}
+  // expected-warning@-2 {{Division by zero}}
+}
Index: clang/test/Analysis/bitwise-nullability.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/bitwise-nullability.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_analyze_cc1 \
+// RUN:  -analyzer-checker=core \
+// RUN:  -analyzer-output=text -verify %s
+
+typedef unsigned long long uint64_t;
+
+void test_null_lhs_range_to_non_null_result_infeasible(uint64_t Magic) {
+  uint64_t MaskedMagic = Magic & (0xffffffffffffffffULL >> 13);
+
+  if (Magic) {
+    // no-note: 'Assuming 'Magic' is 0' was here.
+    return;
+  }
+
+  if (MaskedMagic) {
+    // no-note: 'Assuming 'MaskedMagic' is not equal to 0' was here.
+    (void)(1 / Magic); // no-warning
+  }
+}
+
+void test_non_null_lhs_range_to_null_result_feasible(uint64_t Magic) {
+  uint64_t MaskedMagic = Magic & (0xffffffffffffffffULL >> 13);
+
+  if (!Magic) {
+    // expected-note@-1 {{Assuming 'Magic' is not equal to 0}}
+    // expected-note@-2 {{Taking false branch}}
+    return;
+  }
+
+  if (!MaskedMagic) {
+    // expected-note@-1 {{Assuming 'MaskedMagic' is 0}}
+    // expected-note@-2 {{Taking true branch}}
+    (void)(1 / !Magic);
+    // expected-note@-1 {{'Magic' is not equal to 0}}
+    // expected-note@-2 {{Division by zero}}
+    // expected-warning@-3 {{Division by zero}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -476,6 +476,51 @@
   return Input;
 }
 
+// We do not support evaluating bitwise operations, so that when we check for
+// their results being null we create a new assumption whether the current new
+// symbol is null or non-null. If we are on the non-null assumption's branch
+// we need to check the left-hand side operand's constraint range informations:
+// - It if contradicts with the forming new range 'RS' then it returns a null
+//   state as it is an impossible condition.
+// - Otherwise it removes the nullability from its ranges as we know that it
+//   cannot be null on that branch.
+static ProgramStateRef applyBitwiseRanges(ProgramStateRef State,
+                                          BasicValueFactory &BV,
+                                          RangeSet::Factory &F, RangeSet RS,
+                                          SymbolRef Sym) {
+  if (RS.isEmpty())
+    return State;
+
+  // If we cannot be sure whether the value is non-null, do nothing.
+  const llvm::APSInt &Zero = BV.getAPSIntType(Sym->getType()).getZeroValue();
+  if (!RS.Intersect(BV, F, Zero, Zero).isEmpty())
+    return State;
+
+  const SymIntExpr *SIE = dyn_cast<SymIntExpr>(Sym);
+  if (!SIE)
+    return State;
+
+  if (!BinaryOperator::isBitwiseOrShiftOp(SIE->getOpcode()))
+    return State;
+
+  ConstraintRangeTy Constraints = State->get<ConstraintRange>();
+  const SymExpr *CurrentSym = SIE->getLHS();
+  if (const RangeSet *CurrentRS = Constraints.lookup(CurrentSym)) {
+    const RangeSet NewRS = assumeNonZero(BV, F, CurrentSym, *CurrentRS);
+
+    // If the 'NewRS' is not empty it means the 'CurrentSym' is not assumed
+    // to be concrete zero, so it does not contradicts with the non-null
+    // assumption and we could apply the new constraint ranges.
+    if (!NewRS.isEmpty()) {
+      State = State->set<ConstraintRange>(CurrentSym, NewRS);
+    } else {
+      return nullptr;
+    }
+  }
+
+  return State;
+}
+
 RangeSet RangeConstraintManager::getRange(ProgramStateRef State,
                                           SymbolRef Sym) {
   ConstraintRangeTy::data_type *V = State->get<ConstraintRange>(Sym);
@@ -567,6 +612,10 @@
   // [Int-Adjustment+1, Int-Adjustment-1]
   // Notice that the lower bound is greater than the upper bound.
   RangeSet New = getRange(St, Sym).Intersect(getBasicVals(), F, Upper, Lower);
+
+  if (!(St = applyBitwiseRanges(St, getBasicVals(), F, New, Sym)))
+    return nullptr;
+
   return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
 }
 
@@ -582,6 +631,10 @@
   // [Int-Adjustment, Int-Adjustment]
   llvm::APSInt AdjInt = AdjustmentType.convert(Int) - Adjustment;
   RangeSet New = getRange(St, Sym).Intersect(getBasicVals(), F, AdjInt, AdjInt);
+
+  if (!(St = applyBitwiseRanges(St, getBasicVals(), F, New, Sym)))
+    return nullptr;
+
   return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
 }
 
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
@@ -118,6 +118,7 @@
   RangeSet Negate(BasicValueFactory &BV, Factory &F) const;
 
   void print(raw_ostream &os) const;
+  LLVM_DUMP_METHOD void dump() const { print(llvm::errs()); }
 
   bool operator==(const RangeSet &other) const {
     return ranges == other.ranges;
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