From: Ted Kremenek Date: Sat, 17 Oct 2009 07:39:35 +0000 (+0000) Subject: Fix another static analyzer crash due to a corner case in "folding" symbolic values... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9b02034b6461000f8355c9c91118adaf644cbc8a;p=clang Fix another static analyzer crash due to a corner case in "folding" symbolic values that are constrained to be a constant. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84320 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp index 5af4c062e0..4487aa9d30 100644 --- a/lib/Analysis/SimpleSValuator.cpp +++ b/lib/Analysis/SimpleSValuator.cpp @@ -346,24 +346,29 @@ SVal SimpleSValuator::EvalBinOpNN(const GRState *state, nonloc::SymbolVal *slhs = cast(&lhs); SymbolRef Sym = slhs->getSymbol(); - // Does the symbol simplify to a constant? + // Does the symbol simplify to a constant? If so, "fold" the constant + // by setting 'lhs' to a ConcreteInt and try again. if (Sym->getType(ValMgr.getContext())->isIntegerType()) if (const llvm::APSInt *Constant = state->getSymVal(Sym)) { - // For shifts, there is no need to perform any conversions - // of the constant. - if (BinaryOperator::isShiftOp(op)) { - lhs = nonloc::ConcreteInt(*Constant); + // The symbol evaluates to a constant. If necessary, promote the + // folded constant (LHS) to the result type. + BasicValueFactory &BVF = ValMgr.getBasicValueFactory(); + const llvm::APSInt &lhs_I = BVF.Convert(resultTy, *Constant); + lhs = nonloc::ConcreteInt(lhs_I); + + // Also promote the RHS (if necessary). + + // For shifts, it necessary promote the RHS to the result type. + if (BinaryOperator::isShiftOp(op)) continue; - } - // Other cases: do an implicit conversion. This shouldn't be + // Other operators: do an implicit conversion. This shouldn't be // necessary once we support truncation/extension of symbolic values. if (nonloc::ConcreteInt *rhs_I = dyn_cast(&rhs)){ - BasicValueFactory &BVF = ValMgr.getBasicValueFactory(); - lhs = nonloc::ConcreteInt(BVF.Convert(rhs_I->getValue(), - *Constant)); - continue; + rhs = nonloc::ConcreteInt(BVF.Convert(resultTy, rhs_I->getValue())); } + + continue; } if (isa(rhs)) { diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m index 48d1111a60..fcc13a39a4 100644 --- a/test/Analysis/misc-ps.m +++ b/test/Analysis/misc-ps.m @@ -681,21 +681,23 @@ void *rdar7152418_bar(); return 1; } +//===----------------------------------------------------------------------===// // Test constant-folding of symbolic values, automatically handling type -// conversions of the symbol as necessary. Previously this would crash -// once we started eagerly evaluating symbols whose values were constrained -// to a single value. -void test_constant_symbol(signed char x) { +// conversions of the symbol as necessary. +//===----------------------------------------------------------------------===// + + +// Previously this would crash once we started eagerly evaluating symbols whose +// values were constrained to a single value. +void test_symbol_fold_1(signed char x) { while (1) { if (x == ((signed char) 0)) {} } } -// Test constant-folding of symbolic values, where a folded symbolic value is used in a -// bitshift operation. This previously caused a crash because it triggered an assertion -// in APSInt. -void test_symbol_fold_with_shift(unsigned int * p, unsigned int n, - const unsigned int * grumpkin, unsigned int dn) { +// This previously caused a crash because it triggered an assertion in APSInt. +void test_symbol_fold_2(unsigned int * p, unsigned int n, + const unsigned int * grumpkin, unsigned int dn) { unsigned int i; unsigned int tempsub[8]; unsigned int *solgrumpkin = tempsub + n; @@ -704,3 +706,15 @@ void test_symbol_fold_with_shift(unsigned int * p, unsigned int n, for (i <<= 5; i < (n << 5); i++) {} } +// This previously caused a crash because it triggered an assertion in APSInt. +// 'x' would evaluate to a 8-bit constant (because of the return value of +// test_symbol_fold_3_aux()) which would not get properly promoted to an +// integer. +char test_symbol_fold_3_aux(void); +unsigned test_symbol_fold_3(void) { + unsigned x = test_symbol_fold_3_aux(); + if (x == 54) + return (x << 8) | 0x5; + return 0; +} +