llvm/clang/test/Analysis/equality_tracking.c

// RUN: %clang_analyze_cc1 -verify %s \
// RUN:   -analyzer-checker=core,debug.ExprInspection \
// RUN:   -analyzer-config eagerly-assume=false

#define NULL (void *)0

#define UCHAR_MAX (unsigned char)(~0U)
#define CHAR_MAX (char)(UCHAR_MAX & (UCHAR_MAX >> 1))
#define CHAR_MIN (char)(UCHAR_MAX & ~(UCHAR_MAX >> 1))

void clang_analyzer_value(int);
void clang_analyzer_eval(int);
void clang_analyzer_warnIfReached(void);

int getInt(void);

void zeroImpliesEquality(int a, int b) {
  clang_analyzer_eval((a - b) == 0); // expected-warning{{UNKNOWN}}
  if ((a - b) == 0) {
    clang_analyzer_eval(b != a);    // expected-warning{{FALSE}}
    clang_analyzer_eval(b == a);    // expected-warning{{TRUE}}
    clang_analyzer_eval(!(a != b)); // expected-warning{{TRUE}}
    clang_analyzer_eval(!(b == a)); // expected-warning{{FALSE}}
    return;
  }
  clang_analyzer_eval((a - b) == 0); // expected-warning{{FALSE}}
  clang_analyzer_eval(b == a);       // expected-warning{{FALSE}}
  clang_analyzer_eval(b != a);       // expected-warning{{TRUE}}
}

typedef int I32_A;
typedef int I32_B;
void zeroImpliesEqualityWithTypedef(I32_A a, I32_B b) {
  clang_analyzer_eval((a - b) == 0); // expected-warning{{UNKNOWN}}
  if ((a - b) == 0) {
    clang_analyzer_eval(b != a);    // expected-warning{{FALSE}}
    clang_analyzer_eval(b == a);    // expected-warning{{TRUE}}
    clang_analyzer_eval(!(a != b)); // expected-warning{{TRUE}}
    clang_analyzer_eval(!(b == a)); // expected-warning{{FALSE}}
    return;
  }
  clang_analyzer_eval((a - b) == 0); // expected-warning{{FALSE}}
  clang_analyzer_eval(b == a);       // expected-warning{{FALSE}}
  clang_analyzer_eval(b != a);       // expected-warning{{TRUE}}
}

void zeroImpliesReversedEqual(int a, int b) {
  clang_analyzer_eval((b - a) == 0); // expected-warning{{UNKNOWN}}
  if ((b - a) == 0) {
    clang_analyzer_eval(b != a); // expected-warning{{FALSE}}
    clang_analyzer_eval(b == a); // expected-warning{{TRUE}}
    return;
  }
  clang_analyzer_eval((b - a) == 0); // expected-warning{{FALSE}}
  clang_analyzer_eval(b == a);       // expected-warning{{FALSE}}
  clang_analyzer_eval(b != a);       // expected-warning{{TRUE}}
}

void canonicalEqual(int a, int b) {
  clang_analyzer_eval(a == b); // expected-warning{{UNKNOWN}}
  if (a == b) {
    clang_analyzer_eval(b == a); // expected-warning{{TRUE}}
    return;
  }
  clang_analyzer_eval(a == b); // expected-warning{{FALSE}}
  clang_analyzer_eval(b == a); // expected-warning{{FALSE}}
}

void test(int a, int b, int c, int d) {
  if (a == b && c == d) {
    if (a == 0 && b == d) {
      clang_analyzer_eval(c == 0); // expected-warning{{TRUE}}
    }
    c = 10;
    if (b == d) {
      clang_analyzer_eval(c == 10); // expected-warning{{TRUE}}
      clang_analyzer_eval(d == 10); // expected-warning{{UNKNOWN}}
                                    // expected-warning@-1{{FALSE}}
      clang_analyzer_eval(b == a);  // expected-warning{{TRUE}}
      clang_analyzer_eval(a == d);  // expected-warning{{TRUE}}

      b = getInt();
      clang_analyzer_eval(a == d); // expected-warning{{TRUE}}
      clang_analyzer_eval(a == b); // expected-warning{{UNKNOWN}}
    }
  }

  if (a != b && b == c) {
    if (c == 42) {
      clang_analyzer_eval(b == 42); // expected-warning{{TRUE}}
      clang_analyzer_eval(a != 42); // expected-warning{{TRUE}}
    }
  }
}

void testIntersection(int a, int b, int c) {
  if (a < 42 && b > 15 && c >= 25 && c <= 30) {
    if (a != b)
      return;

    clang_analyzer_eval(a > 15);  // expected-warning{{TRUE}}
    clang_analyzer_eval(b < 42);  // expected-warning{{TRUE}}
    clang_analyzer_eval(a <= 30); // expected-warning{{UNKNOWN}}

    if (c == b) {
      // For all equal symbols, we should track the minimal common range.
      //
      // Also, it should be noted that c is dead at this point, but the
      // constraint initially associated with c is still around.
      clang_analyzer_eval(a >= 25 && a <= 30); // expected-warning{{TRUE}}
      clang_analyzer_eval(b >= 25 && b <= 30); // expected-warning{{TRUE}}
    }
  }
}

void testPromotion(int a, char b) {
  if (b > 10) {
    if (a == b) {
      // FIXME: support transferring char ranges onto equal int symbols
      //        when char is promoted to int
      clang_analyzer_eval(a > 10);        // expected-warning{{UNKNOWN}}
      clang_analyzer_eval(a <= CHAR_MAX); // expected-warning{{UNKNOWN}}
    }
  }
}

void testPromotionOnlyTypes(int a, char b) {
  if (a == b) {
    // FIXME: support transferring char ranges onto equal int symbols
    //        when char is promoted to int
    clang_analyzer_eval(a <= CHAR_MAX); // expected-warning{{UNKNOWN}}
  }
}

void testDowncast(int a, unsigned char b) {
  if (a <= -10) {
    if ((unsigned char)a == b) {
      // Even though ranges for a and b do not intersect,
      // ranges for (unsigned char)a and b do.
      clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
    }
    if (a == b) {
      // FIXME: This case on the other hand is different, it shouldn't be
      //        reachable.  However, the corrent symbolic information available
      //        to the solver doesn't allow it to distinguish this expression
      //        from the previous one.
      clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
    }
  }
}

void testPointers(int *a, int *b, int *c, int *d) {
  if (a == b && c == d) {
    if (a == NULL && b == d) {
      clang_analyzer_eval(c == NULL); // expected-warning{{TRUE}}
    }
  }

  if (a != b && b == c) {
    if (c == NULL) {
      clang_analyzer_eval(a != NULL); // expected-warning{{TRUE}}
    }
  }
}

void testDisequalitiesAfter(int a, int b, int c) {
  if (a >= 10 && b <= 42) {
    if (a == b && c == 15 && c != a) {
      clang_analyzer_eval(b != c);  // expected-warning{{TRUE}}
      clang_analyzer_eval(a != 15); // expected-warning{{TRUE}}
      clang_analyzer_eval(b != 15); // expected-warning{{TRUE}}
      clang_analyzer_eval(b >= 10); // expected-warning{{TRUE}}
      clang_analyzer_eval(a <= 42); // expected-warning{{TRUE}}
    }
  }
}

void testDisequalitiesBefore(int a, int b, int c) {
  if (a >= 10 && b <= 42 && c == 15) {
    if (a == b && c != a) {
      clang_analyzer_eval(b != c);  // expected-warning{{TRUE}}
      clang_analyzer_eval(a != 15); // expected-warning{{TRUE}}
      clang_analyzer_eval(b != 15); // expected-warning{{TRUE}}
      clang_analyzer_eval(b >= 10); // expected-warning{{TRUE}}
      clang_analyzer_eval(a <= 42); // expected-warning{{TRUE}}
    }
  }
}

void avoidInfeasibleConstraintsForClasses(int a, int b) {
  if (a >= 0 && a <= 10 && b >= 20 && b <= 50) {
    if ((b - a) == 0) {
      clang_analyzer_warnIfReached(); // no warning
    }
    if (a == b) {
      clang_analyzer_warnIfReached(); // no warning
    }
    if (a != b) {
      clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
    } else {
      clang_analyzer_warnIfReached(); // no warning
    }
  }
}

void avoidInfeasibleConstraintforGT(int a, int b) {
  int c = b - a;
  if (c <= 0)
    return;
  // c > 0
  // b - a > 0
  // b > a
  if (a != b) {
    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
    return;
  }
  clang_analyzer_warnIfReached(); // no warning
  // a == b
  if (c < 0)
    ;
}

void avoidInfeasibleConstraintforLT(int a, int b) {
  int c = b - a;
  if (c >= 0)
    return;
  // c < 0
  // b - a < 0
  // b < a
  if (a != b) {
    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
    return;
  }
  clang_analyzer_warnIfReached(); // no warning
  // a == b
  if (c < 0)
    ;
}

void implyDisequalityFromGT(int a, int b) {
  if (a > b) {
    clang_analyzer_eval(a == b); // expected-warning{{FALSE}}
    clang_analyzer_eval(a != b); // expected-warning{{TRUE}}
  }
}

void implyDisequalityFromLT(int a, int b) {
  if (a < b) {
    clang_analyzer_eval(a == b); // expected-warning{{FALSE}}
    clang_analyzer_eval(a != b); // expected-warning{{TRUE}}
  }
}

void deletePointBefore(int x, int tmp) {
  if(tmp == 0)
    if(x != tmp)
     clang_analyzer_value(x); // expected-warning {{32s:{ [-2147483648, -1], [1, 2147483647] }}}
}

void deletePointAfter(int x, int tmp) {
  if(x != tmp)
    if(tmp == 2147483647)
      clang_analyzer_value(x); // expected-warning {{32s:{ [-2147483648, 2147483646] }}}
}

void deleteTwoPoints(int x, int tmp1, int tmp2) {
  if(x != tmp1) {
    if (tmp1 == 42 && tmp2 == 87) {
      clang_analyzer_value(x); // expected-warning {{32s:{ [-2147483648, 41], [43, 2147483647] }}}
      if(x != tmp2)
        clang_analyzer_value(x); // expected-warning {{32s:{ [-2147483648, 41], [43, 86], [88, 2147483647] }}}
    }
  }
}

void deleteAllPoints(unsigned char x, unsigned char *arr) {

#define cond(n) \
arr[n##0] == n##0 && \
arr[n##1] == n##1 && \
arr[n##2] == n##2 && \
arr[n##3] == n##3 && \
arr[n##4] == n##4 && \
arr[n##5] == n##5 && \
arr[n##6] == n##6 && \
arr[n##7] == n##7 && \
arr[n##8] == n##8 && \
arr[n##9] == n##9 && \

#define condX(n) \
arr[n##0] != x && \
arr[n##1] != x && \
arr[n##2] != x && \
arr[n##3] != x && \
arr[n##4] != x && \
arr[n##5] != x && \
arr[n##6] != x && \
arr[n##7] != x && \
arr[n##8] != x && \
arr[n##9] != x && \

  clang_analyzer_value(x); // expected-warning {{{ [0, 255] }}}
  if (
    cond()  // 0  .. 9
    cond(1) // 10 .. 19
    cond(2) // 20 .. 29
    cond(3) // 30 .. 39
    cond(4) // 40 .. 49
    cond(5) // 50 .. 59
    cond(6) // 60 .. 69
    cond(7) // 70 .. 79
    cond(8) // 80 .. 89
    cond(9) // 90 .. 99
    cond(10) // 100 .. 209
    cond(11) // 110 .. 219
    cond(12) // 120 .. 229
    cond(13) // 130 .. 239
    cond(14) // 140 .. 249
    cond(15) // 150 .. 259
    cond(16) // 160 .. 269
    cond(17) // 170 .. 279
    cond(18) // 180 .. 289
    cond(19) // 190 .. 199
    cond(20) // 200 .. 209
    cond(21) // 210 .. 219
    cond(22) // 220 .. 229
    cond(23) // 230 .. 239
    cond(24) // 240 .. 249
    arr[250] == 250 &&
    arr[251] == 251 &&
    arr[252] == 252 &&
    arr[253] == 253 &&
    arr[254] == 254 &&
    arr[255] == 255
    ) {
    if (
      condX()  // 0  .. 9
      condX(1) // 10 .. 19
      condX(2) // 20 .. 29
      condX(3) // 30 .. 39
      condX(4) // 40 .. 49
      condX(5) // 50 .. 59
      condX(6) // 60 .. 69
      condX(7) // 70 .. 79
      condX(8) // 80 .. 89
      condX(9) // 90 .. 99
      condX(10) // 100 .. 209
      condX(11) // 110 .. 219
      condX(12) // 120 .. 229
      condX(13) // 130 .. 239
      condX(14) // 140 .. 249
      condX(15) // 150 .. 259
      condX(16) // 160 .. 269
      condX(17) // 170 .. 279
      condX(18) // 180 .. 289
      condX(19) // 190 .. 199
      condX(20) // 200 .. 209
      condX(21) // 210 .. 219
      condX(22) // 220 .. 229
      condX(23) // 230 .. 239
      arr[240] != x &&
      arr[241] != x &&
      arr[242] != x &&
      arr[243] != x &&
      arr[244] != x &&
      arr[245] != x &&
      arr[246] != x &&
      arr[247] != x &&
      arr[248] != x &&
      arr[249] != x
      ) {
      clang_analyzer_value(x); // expected-warning {{{ [250, 255] }}}
      if (
      arr[250] != x &&
      arr[251] != x &&
      //skip arr[252]
      arr[253] != x &&
      arr[254] != x &&
      arr[255] != x
      ) {
        clang_analyzer_value(x); // expected-warning {{32s:252}}
        if (arr[252] != x) {
          clang_analyzer_warnIfReached(); // unreachable
        }
      }
    }
  }
}