// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.deadcode.UnreachableCode,unix.Malloc -verify -analyzer-constraints=range %s // These are used to trigger warnings. typedef typeof(sizeof(int)) size_t; void *malloc(size_t); void free(void *); #define NULL ((void*)0) #define UINT_MAX (~0U) #define INT_MAX (UINT_MAX & (UINT_MAX >> 1)) #define INT_MIN (-INT_MAX - 1) // Each of these adjusted ranges has an adjustment small enough to split the // solution range across an overflow boundary (Min for <, Max for >). // This corresponds to one set of branches in RangeConstraintManager. void smallAdjustmentGT (unsigned a) { void *b = NULL; if (a+2 > 1) b = malloc(1); if (a == UINT_MAX-1 || a == UINT_MAX) return; // no-warning else if (a < UINT_MAX-1) free(b); return; // no-warning } void smallAdjustmentGE (unsigned a) { void *b = NULL; if (a+2 >= 1) b = malloc(1); if (a == UINT_MAX-1) return; // no-warning else if (a < UINT_MAX-1 || a == UINT_MAX) free(b); return; // no-warning } void smallAdjustmentLT (unsigned a) { void *b = NULL; if (a+1 < 2) b = malloc(1); if (a == 0 || a == UINT_MAX) free(b); return; // no-warning } void smallAdjustmentLE (unsigned a) { void *b = NULL; if (a+1 <= 2) b = malloc(1); if (a == 0 || a == 1 || a == UINT_MAX) free(b); return; // no-warning } // Each of these adjusted ranges has an adjustment large enough to push the // comparison value over an overflow boundary (Min for <, Max for >). // This corresponds to one set of branches in RangeConstraintManager. void largeAdjustmentGT (unsigned a) { void *b = NULL; if (a-2 > UINT_MAX-1) b = malloc(1); if (a == 1 || a == 0) free(b); else if (a > 1) free(b); return; // no-warning } void largeAdjustmentGE (unsigned a) { void *b = NULL; if (a-2 >= UINT_MAX-1) b = malloc(1); if (a > 1) return; // no-warning else if (a == 1 || a == 0) free(b); return; // no-warning } void largeAdjustmentLT (unsigned a) { void *b = NULL; if (a+2 < 1) b = malloc(1); if (a == UINT_MAX-1 || a == UINT_MAX) free(b); else if (a < UINT_MAX-1) return; // no-warning return; // no-warning } void largeAdjustmentLE (unsigned a) { void *b = NULL; if (a+2 <= 1) b = malloc(1); if (a < UINT_MAX-1) return; // no-warning else if (a == UINT_MAX-1 || a == UINT_MAX) free(b); return; // no-warning } // Test the nine cases in RangeConstraintManager's pinning logic. void mixedComparisons1(signed char a) { // Case 1: The range is entirely below the symbol's range. int min = INT_MIN; if ((a - 2) < (min + 5LL)) return; // expected-warning{{never executed}} if (a == 0) return; // no-warning if (a == 0x7F) return; // no-warning if (a == -0x80) return; // no-warning return; // no-warning } void mixedComparisons2(signed char a) { // Case 2: Only the lower end of the range is outside. if ((a - 5) < (-0x81LL)) { if (a == 0) return; // expected-warning{{never executed}} if (a == 0x7F) return; // expected-warning{{never executed}} if (a == -0x80) return; // no-warning return; // no-warning } else { return; // no-warning } } void mixedComparisons3(signed char a) { // Case 3: The entire symbol range is covered. if ((a - 0x200) < -0x100LL) { if (a == 0) return; // no-warning if (a == 0x7F) return; // no-warning if (a == -0x80) return; // no-warning return; // no-warning } else { return; // expected-warning{{never executed}} } } void mixedComparisons4(signed char a) { // Case 4: The range wraps around, but the lower wrap is out-of-range. if ((a - 5) > 0LL) { if (a == 0) return; // expected-warning{{never executed}} if (a == 0x7F) return; // no-warning if (a == -0x80) return; // expected-warning{{never executed}} return; // no-warning } else { return; // no-warning } } void mixedComparisons5(signed char a) { // Case 5a: The range is inside and does not wrap. if ((a + 5) == 0LL) { if (a == 0) return; // expected-warning{{never executed}} if (a == 0x7F) return; // expected-warning{{never executed}} if (a == -0x80) return; // expected-warning{{never executed}} return; // no-warning } else { return; // no-warning } } void mixedComparisons5Wrap(signed char a) { // Case 5b: The range is inside and does wrap. if ((a + 5) != 0LL) { if (a == 0) return; // no-warning if (a == 0x7F) return; // no-warning if (a == -0x80) return; // no-warning return; // no-warning } else { return; // no-warning } } void mixedComparisons6(signed char a) { // Case 6: Only the upper end of the range is outside. if ((a + 5) > 0x81LL) { if (a == 0) return; // expected-warning{{never executed}} if (a == 0x7F) return; // no-warning if (a == -0x80) return; // expected-warning{{never executed}} return; // no-warning } else { return; // no-warning } } void mixedComparisons7(signed char a) { // Case 7: The range wraps around but is entirely outside the symbol's range. int min = INT_MIN; if ((a + 2) < (min + 5LL)) return; // expected-warning{{never executed}} if (a == 0) return; // no-warning if (a == 0x7F) return; // no-warning if (a == -0x80) return; // no-warning return; // no-warning } void mixedComparisons8(signed char a) { // Case 8: The range wraps, but the upper wrap is out of range. if ((a + 5) < 0LL) { if (a == 0) return; // expected-warning{{never executed}} if (a == 0x7F) return; // expected-warning{{never executed}} if (a == -0x80) return; // no-warning return; // no-warning } else { return; // no-warning } } void mixedComparisons9(signed char a) { // Case 9: The range is entirely above the symbol's range. int max = INT_MAX; if ((a + 2) > (max - 5LL)) return; // expected-warning{{never executed}} if (a == 0) return; // no-warning if (a == 0x7F) return; // no-warning if (a == -0x80) return; // no-warning return; // no-warning }