FlatStoreManager::RegionInterval FlatStoreManager::RegionToInterval(const MemRegion *R) { switch (R->getKind()) { case MemRegion::VarRegionKind: { QualType T = cast<VarRegion>(R)->getValueType(); int64_t Size = Ctx.getTypeSize(T); return RegionInterval(R, 0, Size-1); } case MemRegion::ElementRegionKind: case MemRegion::FieldRegionKind: { RegionOffset Offset = R->getAsOffset(); // We cannot compute offset for all regions, for example, elements // with symbolic offsets. if (!Offset.getRegion()) return RegionInterval(0, 0, 0); int64_t Start = Offset.getOffset(); int64_t Size = Ctx.getTypeSize(cast<TypedRegion>(R)->getValueType()); return RegionInterval(Offset.getRegion(), Start, Start+Size); } default: llvm_unreachable("Region kind unhandled."); return RegionInterval(0, 0, 0); } }
// FIXME: all this logic will change if/when we have MemRegion::getLocation(). SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op, Loc lhs, Loc rhs, QualType resultTy) { // Only comparisons and subtractions are valid operations on two pointers. // See [C99 6.5.5 through 6.5.14] or [C++0x 5.6 through 5.15]. // However, if a pointer is casted to an integer, evalBinOpNN may end up // calling this function with another operation (PR7527). We don't attempt to // model this for now, but it could be useful, particularly when the // "location" is actually an integer value that's been passed through a void*. if (!(BinaryOperator::isComparisonOp(op) || op == BO_Sub)) return UnknownVal(); // Special cases for when both sides are identical. if (lhs == rhs) { switch (op) { default: llvm_unreachable("Unimplemented operation for two identical values"); case BO_Sub: return makeZeroVal(resultTy); case BO_EQ: case BO_LE: case BO_GE: return makeTruthVal(true, resultTy); case BO_NE: case BO_LT: case BO_GT: return makeTruthVal(false, resultTy); } } switch (lhs.getSubKind()) { default: llvm_unreachable("Ordering not implemented for this Loc."); case loc::GotoLabelKind: // The only thing we know about labels is that they're non-null. if (rhs.isZeroConstant()) { switch (op) { default: break; case BO_Sub: return evalCastFromLoc(lhs, resultTy); case BO_EQ: case BO_LE: case BO_LT: return makeTruthVal(false, resultTy); case BO_NE: case BO_GT: case BO_GE: return makeTruthVal(true, resultTy); } } // There may be two labels for the same location, and a function region may // have the same address as a label at the start of the function (depending // on the ABI). // FIXME: we can probably do a comparison against other MemRegions, though. // FIXME: is there a way to tell if two labels refer to the same location? return UnknownVal(); case loc::ConcreteIntKind: { // If one of the operands is a symbol and the other is a constant, // build an expression for use by the constraint manager. if (SymbolRef rSym = rhs.getAsLocSymbol()) { // We can only build expressions with symbols on the left, // so we need a reversible operator. if (!BinaryOperator::isComparisonOp(op)) return UnknownVal(); const llvm::APSInt &lVal = lhs.castAs<loc::ConcreteInt>().getValue(); op = BinaryOperator::reverseComparisonOp(op); return makeNonLoc(rSym, op, lVal, resultTy); } // If both operands are constants, just perform the operation. if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) { SVal ResultVal = lhs.castAs<loc::ConcreteInt>().evalBinOp(BasicVals, op, *rInt); if (Optional<NonLoc> Result = ResultVal.getAs<NonLoc>()) return evalCastFromNonLoc(*Result, resultTy); assert(!ResultVal.getAs<Loc>() && "Loc-Loc ops should not produce Locs"); return UnknownVal(); } // Special case comparisons against NULL. // This must come after the test if the RHS is a symbol, which is used to // build constraints. The address of any non-symbolic region is guaranteed // to be non-NULL, as is any label. assert(rhs.getAs<loc::MemRegionVal>() || rhs.getAs<loc::GotoLabel>()); if (lhs.isZeroConstant()) { switch (op) { default: break; case BO_EQ: case BO_GT: case BO_GE: return makeTruthVal(false, resultTy); case BO_NE: case BO_LT: case BO_LE: return makeTruthVal(true, resultTy); } } // Comparing an arbitrary integer to a region or label address is // completely unknowable. return UnknownVal(); } case loc::MemRegionValKind: { if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) { // If one of the operands is a symbol and the other is a constant, // build an expression for use by the constraint manager. if (SymbolRef lSym = lhs.getAsLocSymbol(true)) return MakeSymIntVal(lSym, op, rInt->getValue(), resultTy); // Special case comparisons to NULL. // This must come after the test if the LHS is a symbol, which is used to // build constraints. The address of any non-symbolic region is guaranteed // to be non-NULL. if (rInt->isZeroConstant()) { if (op == BO_Sub) return evalCastFromLoc(lhs, resultTy); if (BinaryOperator::isComparisonOp(op)) { QualType boolType = getContext().BoolTy; NonLoc l = evalCastFromLoc(lhs, boolType).castAs<NonLoc>(); NonLoc r = makeTruthVal(false, boolType).castAs<NonLoc>(); return evalBinOpNN(state, op, l, r, resultTy); } } // Comparing a region to an arbitrary integer is completely unknowable. return UnknownVal(); } // Get both values as regions, if possible. const MemRegion *LeftMR = lhs.getAsRegion(); assert(LeftMR && "MemRegionValKind SVal doesn't have a region!"); const MemRegion *RightMR = rhs.getAsRegion(); if (!RightMR) // The RHS is probably a label, which in theory could address a region. // FIXME: we can probably make a more useful statement about non-code // regions, though. return UnknownVal(); const MemRegion *LeftBase = LeftMR->getBaseRegion(); const MemRegion *RightBase = RightMR->getBaseRegion(); const MemSpaceRegion *LeftMS = LeftBase->getMemorySpace(); const MemSpaceRegion *RightMS = RightBase->getMemorySpace(); const MemSpaceRegion *UnknownMS = MemMgr.getUnknownRegion(); // If the two regions are from different known memory spaces they cannot be // equal. Also, assume that no symbolic region (whose memory space is // unknown) is on the stack. if (LeftMS != RightMS && ((LeftMS != UnknownMS && RightMS != UnknownMS) || (isa<StackSpaceRegion>(LeftMS) || isa<StackSpaceRegion>(RightMS)))) { switch (op) { default: return UnknownVal(); case BO_EQ: return makeTruthVal(false, resultTy); case BO_NE: return makeTruthVal(true, resultTy); } } // If both values wrap regions, see if they're from different base regions. // Note, heap base symbolic regions are assumed to not alias with // each other; for example, we assume that malloc returns different address // on each invocation. // FIXME: ObjC object pointers always reside on the heap, but currently // we treat their memory space as unknown, because symbolic pointers // to ObjC objects may alias. There should be a way to construct // possibly-aliasing heap-based regions. For instance, MacOSXApiChecker // guesses memory space for ObjC object pointers manually instead of // relying on us. if (LeftBase != RightBase && ((!isa<SymbolicRegion>(LeftBase) && !isa<SymbolicRegion>(RightBase)) || (isa<HeapSpaceRegion>(LeftMS) || isa<HeapSpaceRegion>(RightMS))) ){ switch (op) { default: return UnknownVal(); case BO_EQ: return makeTruthVal(false, resultTy); case BO_NE: return makeTruthVal(true, resultTy); } } // Handle special cases for when both regions are element regions. const ElementRegion *RightER = dyn_cast<ElementRegion>(RightMR); const ElementRegion *LeftER = dyn_cast<ElementRegion>(LeftMR); if (RightER && LeftER) { // Next, see if the two ERs have the same super-region and matching types. // FIXME: This should do something useful even if the types don't match, // though if both indexes are constant the RegionRawOffset path will // give the correct answer. if (LeftER->getSuperRegion() == RightER->getSuperRegion() && LeftER->getElementType() == RightER->getElementType()) { // Get the left index and cast it to the correct type. // If the index is unknown or undefined, bail out here. SVal LeftIndexVal = LeftER->getIndex(); Optional<NonLoc> LeftIndex = LeftIndexVal.getAs<NonLoc>(); if (!LeftIndex) return UnknownVal(); LeftIndexVal = evalCastFromNonLoc(*LeftIndex, ArrayIndexTy); LeftIndex = LeftIndexVal.getAs<NonLoc>(); if (!LeftIndex) return UnknownVal(); // Do the same for the right index. SVal RightIndexVal = RightER->getIndex(); Optional<NonLoc> RightIndex = RightIndexVal.getAs<NonLoc>(); if (!RightIndex) return UnknownVal(); RightIndexVal = evalCastFromNonLoc(*RightIndex, ArrayIndexTy); RightIndex = RightIndexVal.getAs<NonLoc>(); if (!RightIndex) return UnknownVal(); // Actually perform the operation. // evalBinOpNN expects the two indexes to already be the right type. return evalBinOpNN(state, op, *LeftIndex, *RightIndex, resultTy); } } // Special handling of the FieldRegions, even with symbolic offsets. const FieldRegion *RightFR = dyn_cast<FieldRegion>(RightMR); const FieldRegion *LeftFR = dyn_cast<FieldRegion>(LeftMR); if (RightFR && LeftFR) { SVal R = evalBinOpFieldRegionFieldRegion(LeftFR, RightFR, op, resultTy, *this); if (!R.isUnknown()) return R; } // Compare the regions using the raw offsets. RegionOffset LeftOffset = LeftMR->getAsOffset(); RegionOffset RightOffset = RightMR->getAsOffset(); if (LeftOffset.getRegion() != nullptr && LeftOffset.getRegion() == RightOffset.getRegion() && !LeftOffset.hasSymbolicOffset() && !RightOffset.hasSymbolicOffset()) { int64_t left = LeftOffset.getOffset(); int64_t right = RightOffset.getOffset(); switch (op) { default: return UnknownVal(); case BO_LT: return makeTruthVal(left < right, resultTy); case BO_GT: return makeTruthVal(left > right, resultTy); case BO_LE: return makeTruthVal(left <= right, resultTy); case BO_GE: return makeTruthVal(left >= right, resultTy); case BO_EQ: return makeTruthVal(left == right, resultTy); case BO_NE: return makeTruthVal(left != right, resultTy); } } // At this point we're not going to get a good answer, but we can try // conjuring an expression instead. SymbolRef LHSSym = lhs.getAsLocSymbol(); SymbolRef RHSSym = rhs.getAsLocSymbol(); if (LHSSym && RHSSym) return makeNonLoc(LHSSym, op, RHSSym, resultTy); // If we get here, we have no way of comparing the regions. return UnknownVal(); } } }