static bool pointedUnqualifiedTypesAreEqual(QualType T1, QualType T2) { while ((T1->isPointerType() && T2->isPointerType()) || (T1->isReferenceType() && T2->isReferenceType())) { T1 = T1->getPointeeType(); T2 = T2->getPointeeType(); } return T1.getUnqualifiedType() == T2.getUnqualifiedType(); }
bool pointedTypesAreEqual(QualType SourceType, QualType DestType) { SourceType = SourceType.getNonReferenceType(); DestType = DestType.getNonReferenceType(); while (SourceType->isPointerType() && DestType->isPointerType()) { SourceType = SourceType->getPointeeType(); DestType = DestType->getPointeeType(); } return SourceType.getUnqualifiedType() == DestType.getUnqualifiedType(); }
bool needsConstCast(QualType SourceType, QualType DestType) { SourceType = SourceType.getNonReferenceType(); DestType = DestType.getNonReferenceType(); while (SourceType->isPointerType() && DestType->isPointerType()) { SourceType = SourceType->getPointeeType(); DestType = DestType->getPointeeType(); if (SourceType.isConstQualified() && !DestType.isConstQualified()) return true; } return false; }
static bool needsConstCast(QualType SourceType, QualType DestType) { while ((SourceType->isPointerType() && DestType->isPointerType()) || (SourceType->isReferenceType() && DestType->isReferenceType())) { SourceType = SourceType->getPointeeType(); DestType = DestType->getPointeeType(); if (SourceType.isConstQualified() && !DestType.isConstQualified()) { return (SourceType->isPointerType() == DestType->isPointerType()) && (SourceType->isReferenceType() == DestType->isReferenceType()); } } return false; }
bool ExprTypeAnalyser::checkExplicitCast(const ExplicitCastExpr* expr, QualType DestType, QualType SrcType) { // C99 6.5.4p2: the cast type needs to be void or scalar and the expression if (!DestType.isScalarType()) { // Dont allow any cast to non-scalar StringBuilder buf1(MAX_LEN_TYPENAME); StringBuilder buf2(MAX_LEN_TYPENAME); DestType.DiagName(buf1); SrcType.DiagName(buf2); Diags.Report(expr->getLocation(), diag::err_typecheck_cond_expect_scalar) << buf1 << buf2 << expr->getSourceRange(); return false; } // If either type is a pointer, the other type has to be either an // integer or a pointer // TODO decide if Enums are arithmatic types or not (they are in C99, not is C++0x) if (DestType.isPointerType()) { if (SrcType.isPointerType()) { // allow all pointer casts return true; } else { // only allow cast to pointer from uint32/64 (pointer size) const BuiltinType* BT = dyncast<BuiltinType>(SrcType.getCanonicalType()); // TODO use TargetInfo to check if 32-bit if (BT && BT->getKind() == BuiltinType::UInt64) return true; QualType expected = Type::UInt64(); StringBuilder buf1(MAX_LEN_TYPENAME); expected.DiagName(buf1); Diags.Report(expr->getLocation(), diag::err_cast_nonword_to_pointer) << buf1; } } else { if (SrcType.isPointerType()) { // only allow cast to uint32/64 (pointer size) const BuiltinType* BT = dyncast<BuiltinType>(DestType.getCanonicalType()); // TODO use TargetInfo to check if 32-bit if (BT && BT->getKind() == BuiltinType::UInt64) return true; QualType expected = Type::UInt64(); StringBuilder buf1(MAX_LEN_TYPENAME); expected.DiagName(buf1); Diags.Report(expr->getLocation(), diag::err_cast_pointer_to_nonword) << buf1; } else { // check non-pointer to non-pointer type // TODO make this top level function? (switch on src-type) return checkNonPointerCast(expr, DestType, SrcType); } } return false; }
void FixedAddressChecker::checkPreStmt(const BinaryOperator *B, CheckerContext &C) const { // Using a fixed address is not portable because that address will probably // not be valid in all environments or platforms. if (B->getOpcode() != BO_Assign) return; QualType T = B->getType(); if (!T->isPointerType()) return; SVal RV = C.getSVal(B->getRHS()); if (!RV.isConstant() || RV.isZeroConstant()) return; if (ExplodedNode *N = C.generateNonFatalErrorNode()) { if (!BT) BT.reset( new BuiltinBug(this, "Use fixed address", "Using a fixed address is not portable because that " "address will probably not be valid in all " "environments or platforms.")); auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N); R->addRange(B->getRHS()->getSourceRange()); C.emitReport(std::move(R)); } }
void FixedAddressChecker::checkPreStmt(const BinaryOperator *B, CheckerContext &C) const { // Using a fixed address is not portable because that address will probably // not be valid in all environments or platforms. if (B->getOpcode() != BO_Assign) return; QualType T = B->getType(); if (!T->isPointerType()) return; ProgramStateRef state = C.getState(); SVal RV = state->getSVal(B->getRHS(), C.getLocationContext()); if (!RV.isConstant() || RV.isZeroConstant()) return; if (ExplodedNode *N = C.addTransition()) { if (!BT) BT.reset( new BuiltinBug(this, "Use fixed address", "Using a fixed address is not portable because that " "address will probably not be valid in all " "environments or platforms.")); BugReport *R = new BugReport(*BT, BT->getDescription(), N); R->addRange(B->getRHS()->getSourceRange()); C.emitReport(R); } }
ValuePrinterInfo::ValuePrinterInfo(Expr* E, ASTContext* Ctx) : m_Expr(E), m_Context(Ctx), m_Flags(0) { assert(E && "Expression cannot be null!"); assert(Ctx && "ASTContext cannot be null!"); // 1. Get the flags const QualType QT = m_Expr->getType(); if (E->isRValue() || QT.isLocalConstQualified() || QT.isConstant(*Ctx)){ m_Flags |= VPI_Const; } if (QT->isPointerType()) { // treat arrary-to-pointer decay as array: QualType PQT = QT->getPointeeType(); const Type* PTT = PQT.getTypePtr(); if (!PTT || !PTT->isArrayType()) { m_Flags |= VPI_Ptr; if (const RecordType* RT = dyn_cast<RecordType>(QT.getTypePtr())) if (RecordDecl* RD = RT->getDecl()) { CXXRecordDecl* CRD = dyn_cast<CXXRecordDecl>(RD); if (CRD && CRD->isPolymorphic()) m_Flags |= VPI_Polymorphic; } } } }
PathDiagnosticPiece * ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, const bool tookTrue, BugReporterContext &BRC, const LocationContext *LC) { const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); if (!VD) return 0; llvm::SmallString<256> Buf; llvm::raw_svector_ostream Out(Buf); Out << "Assuming '"; VD->getDeclName().printName(Out); Out << "' is "; QualType VDTy = VD->getType(); if (VDTy->isPointerType()) Out << (tookTrue ? "non-null" : "null"); else if (VDTy->isObjCObjectPointerType()) Out << (tookTrue ? "non-nil" : "nil"); else if (VDTy->isScalarType()) Out << (tookTrue ? "not equal to 0" : "0"); else return 0; PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LC); return new PathDiagnosticEventPiece(Loc, Out.str()); }
// CWE-467: Use of sizeof() on a Pointer Type void WalkAST::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (!E->isSizeOf()) return; // If an explicit type is used in the code, usually the coder knows what he is // doing. if (E->isArgumentType()) return; QualType T = E->getTypeOfArgument(); if (T->isPointerType()) { // Many false positives have the form 'sizeof *p'. This is reasonable // because people know what they are doing when they intentionally // dereference the pointer. Expr *ArgEx = E->getArgumentExpr(); if (!isa<DeclRefExpr>(ArgEx->IgnoreParens())) return; SourceRange R = ArgEx->getSourceRange(); BR.EmitBasicReport("Potential unintended use of sizeof() on pointer type", "Logic", "The code calls sizeof() on a pointer type. " "This can produce an unexpected result.", E->getLocStart(), &R, 1); } }
/// CastRetrievedVal - Used by subclasses of StoreManager to implement /// implicit casts that arise from loads from regions that are reinterpreted /// as another region. SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R, QualType castTy) { if (castTy.isNull() || V.isUnknownOrUndef()) return V; // The dispatchCast() call below would convert the int into a float. // What we want, however, is a bit-by-bit reinterpretation of the int // as a float, which usually yields nothing garbage. For now skip casts // from ints to floats. // TODO: What other combinations of types are affected? if (castTy->isFloatingType()) { SymbolRef Sym = V.getAsSymbol(); if (Sym && !Sym->getType()->isFloatingType()) return UnknownVal(); } // When retrieving symbolic pointer and expecting a non-void pointer, // wrap them into element regions of the expected type if necessary. // SValBuilder::dispatchCast() doesn't do that, but it is necessary to // make sure that the retrieved value makes sense, because there's no other // cast in the AST that would tell us to cast it to the correct pointer type. // We might need to do that for non-void pointers as well. // FIXME: We really need a single good function to perform casts for us // correctly every time we need it. if (castTy->isPointerType() && !castTy->isVoidPointerType()) if (const auto *SR = dyn_cast_or_null<SymbolicRegion>(V.getAsRegion())) if (SR->getSymbol()->getType().getCanonicalType() != castTy.getCanonicalType()) return loc::MemRegionVal(castRegion(SR, castTy)); return svalBuilder.dispatchCast(V, castTy); }
void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B) { // Using a fixed address is not portable because that address will probably // not be valid in all environments or platforms. if (B->getOpcode() != BinaryOperator::Assign) return; QualType T = B->getType(); if (!T->isPointerType()) return; const GRState *state = C.getState(); SVal RV = state->getSVal(B->getRHS()); if (!RV.isConstant() || RV.isZeroConstant()) return; if (ExplodedNode *N = C.GenerateNode()) { if (!BT) BT = new BuiltinBug("Use fixed address", "Using a fixed address is not portable because that " "address will probably not be valid in all " "environments or platforms."); RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N); R->addRange(B->getRHS()->getSourceRange()); C.EmitReport(R); } }
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, CastExpr::CastKind Kind, bool isLvalue) { QualType ExprTy = Context.getCanonicalType(Expr->getType()); QualType TypeTy = Context.getCanonicalType(Ty); if (ExprTy == TypeTy) return; if (Expr->getType()->isPointerType() && Ty->isPointerType()) { QualType ExprBaseType = cast<PointerType>(ExprTy)->getPointeeType(); QualType BaseType = cast<PointerType>(TypeTy)->getPointeeType(); if (ExprBaseType.getAddressSpace() != BaseType.getAddressSpace()) { Diag(Expr->getExprLoc(), diag::err_implicit_pointer_address_space_cast) << Expr->getSourceRange(); } } CheckImplicitConversion(Expr, Ty); if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { if (ImpCast->getCastKind() == Kind) { ImpCast->setType(Ty); ImpCast->setLvalueCast(isLvalue); return; } } Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, isLvalue); }
// CWE-467: Use of sizeof() on a Pointer Type void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { if (E->getKind() != UETT_SizeOf) return; // If an explicit type is used in the code, usually the coder knows what he is // doing. if (E->isArgumentType()) return; QualType T = E->getTypeOfArgument(); if (T->isPointerType()) { // Many false positives have the form 'sizeof *p'. This is reasonable // because people know what they are doing when they intentionally // dereference the pointer. Expr *ArgEx = E->getArgumentExpr(); if (!isa<DeclRefExpr>(ArgEx->IgnoreParens())) return; PathDiagnosticLocation ELoc = PathDiagnosticLocation::createBegin(E, BR.getSourceManager(), AC); BR.EmitBasicReport(AC->getDecl(), Checker, "Potential unintended use of sizeof() on pointer type", categories::LogicError, "The code calls sizeof() on a pointer type. " "This can produce an unexpected result.", ELoc, ArgEx->getSourceRange()); } }
void NonConstParameterCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *Parm = Result.Nodes.getNodeAs<ParmVarDecl>("Parm")) { if (const DeclContext *D = Parm->getParentFunctionOrMethod()) { if (const auto *M = dyn_cast<CXXMethodDecl>(D)) { if (M->isVirtual() || M->size_overridden_methods() != 0) return; } } addParm(Parm); } else if (const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("Ctor")) { for (const auto *Parm : Ctor->parameters()) addParm(Parm); for (const auto *Init : Ctor->inits()) markCanNotBeConst(Init->getInit(), true); } else if (const auto *Ref = Result.Nodes.getNodeAs<DeclRefExpr>("Ref")) { setReferenced(Ref); } else if (const auto *S = Result.Nodes.getNodeAs<Stmt>("Mark")) { if (const auto *B = dyn_cast<BinaryOperator>(S)) { if (B->isAssignmentOp()) markCanNotBeConst(B, false); } else if (const auto *CE = dyn_cast<CallExpr>(S)) { // Typically, if a parameter is const then it is fine to make the data // const. But sometimes the data is written even though the parameter // is const. Mark all data passed by address to the function. for (const auto *Arg : CE->arguments()) { markCanNotBeConst(Arg->IgnoreParenCasts(), true); } // Data passed by nonconst reference should not be made const. if (const FunctionDecl *FD = CE->getDirectCallee()) { unsigned ArgNr = 0U; for (const auto *Par : FD->parameters()) { if (ArgNr >= CE->getNumArgs()) break; const Expr *Arg = CE->getArg(ArgNr++); // Is this a non constant reference parameter? const Type *ParType = Par->getType().getTypePtr(); if (!ParType->isReferenceType() || Par->getType().isConstQualified()) continue; markCanNotBeConst(Arg->IgnoreParenCasts(), false); } } } else if (const auto *CE = dyn_cast<CXXConstructExpr>(S)) { for (const auto *Arg : CE->arguments()) { markCanNotBeConst(Arg->IgnoreParenCasts(), true); } } else if (const auto *R = dyn_cast<ReturnStmt>(S)) { markCanNotBeConst(R->getRetValue(), true); } else if (const auto *U = dyn_cast<UnaryOperator>(S)) { markCanNotBeConst(U, true); } } else if (const auto *VD = Result.Nodes.getNodeAs<VarDecl>("Mark")) { const QualType T = VD->getType(); if ((T->isPointerType() && !T->getPointeeType().isConstQualified()) || T->isArrayType()) markCanNotBeConst(VD->getInit(), true); } }
bool ExprTypeAnalyser::checkPointer(QualType left, QualType right, const Expr* expr) const { if (right->isPointerType()) { // TODO return true; } if (right->isArrayType()) { // TODO return true; } error(expr->getLocation(), left, right); return false; }
bool ConditionBRVisitor::patternMatch(const Expr *Ex, raw_ostream &Out, BugReporterContext &BRC, BugReport &report, const ExplodedNode *N, Optional<bool> &prunable) { const Expr *OriginalExpr = Ex; Ex = Ex->IgnoreParenCasts(); if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { const bool quotes = isa<VarDecl>(DR->getDecl()); if (quotes) { Out << '\''; const LocationContext *LCtx = N->getLocationContext(); const ProgramState *state = N->getState().getPtr(); if (const MemRegion *R = state->getLValue(cast<VarDecl>(DR->getDecl()), LCtx).getAsRegion()) { if (report.isInteresting(R)) prunable = false; else { const ProgramState *state = N->getState().getPtr(); SVal V = state->getSVal(R); if (report.isInteresting(V)) prunable = false; } } } Out << DR->getDecl()->getDeclName().getAsString(); if (quotes) Out << '\''; return quotes; } if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(Ex)) { QualType OriginalTy = OriginalExpr->getType(); if (OriginalTy->isPointerType()) { if (IL->getValue() == 0) { Out << "null"; return false; } } else if (OriginalTy->isObjCObjectPointerType()) { if (IL->getValue() == 0) { Out << "nil"; return false; } } Out << IL->getValue(); return false; } return false; }
/// CastsAwayConstness - Check if the pointer conversion from SrcType to /// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by /// the cast checkers. Both arguments must denote pointer (possibly to member) /// types. bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { // Casting away constness is defined in C++ 5.2.11p8 with reference to // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since // the rules are non-trivial. So first we construct Tcv *...cv* as described // in C++ 5.2.11p8. assert((SrcType->isPointerType() || SrcType->isMemberPointerType()) && "Source type is not pointer or pointer to member."); assert((DestType->isPointerType() || DestType->isMemberPointerType()) && "Destination type is not pointer or pointer to member."); QualType UnwrappedSrcType = SrcType, UnwrappedDestType = DestType; llvm::SmallVector<unsigned, 8> cv1, cv2; // Find the qualifications. while (Self.UnwrapSimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) { cv1.push_back(UnwrappedSrcType.getCVRQualifiers()); cv2.push_back(UnwrappedDestType.getCVRQualifiers()); } assert(cv1.size() > 0 && "Must have at least one pointer level."); // Construct void pointers with those qualifiers (in reverse order of // unwrapping, of course). QualType SrcConstruct = Self.Context.VoidTy; QualType DestConstruct = Self.Context.VoidTy; for (llvm::SmallVector<unsigned, 8>::reverse_iterator i1 = cv1.rbegin(), i2 = cv2.rbegin(); i1 != cv1.rend(); ++i1, ++i2) { SrcConstruct = Self.Context.getPointerType( SrcConstruct.getQualifiedType(*i1)); DestConstruct = Self.Context.getPointerType( DestConstruct.getQualifiedType(*i2)); } // Test if they're compatible. return SrcConstruct != DestConstruct && !Self.IsQualificationConversion(SrcConstruct, DestConstruct); }
// Check if type is a "Field() *" pointer type, or alternatively a pointer to // any type in "alt" if provided. bool CheckAllocationsInFunctionVisitor::IsFieldPointer( const QualType& qtype, const char* alt) { if (qtype->isPointerType()) { auto name = qtype->getPointeeType() .getDesugaredType(_mainVisitor->getContext()).getAsString(); return StartsWith(name, "class Memory::WriteBarrierPtr<") || StartsWith(name, "typename WriteBarrierFieldTypeTraits<") || (alt && strstr(alt, name.c_str())); } return false; }
void NonConstParameterCheck::addParm(const ParmVarDecl *Parm) { // Only add nonconst integer/float pointer parameters. const QualType T = Parm->getType(); if (!T->isPointerType() || T->getPointeeType().isConstQualified() || !(T->getPointeeType()->isIntegerType() || T->getPointeeType()->isFloatingType())) return; if (Parameters.find(Parm) != Parameters.end()) return; ParmInfo PI; PI.IsReferenced = false; PI.CanBeConst = true; Parameters[Parm] = PI; }
PathDiagnosticPiece * ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, const bool tookTrue, BugReporterContext &BRC, BugReport &report, const ExplodedNode *N) { const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()); if (!VD) return 0; SmallString<256> Buf; llvm::raw_svector_ostream Out(Buf); Out << "Assuming '"; VD->getDeclName().printName(Out); Out << "' is "; QualType VDTy = VD->getType(); if (VDTy->isPointerType()) Out << (tookTrue ? "non-null" : "null"); else if (VDTy->isObjCObjectPointerType()) Out << (tookTrue ? "non-nil" : "nil"); else if (VDTy->isScalarType()) Out << (tookTrue ? "not equal to 0" : "0"); else return 0; const LocationContext *LCtx = N->getLocationContext(); PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); PathDiagnosticEventPiece *event = new PathDiagnosticEventPiece(Loc, Out.str()); const ProgramState *state = N->getState().getPtr(); if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { if (report.isInteresting(R)) event->setPrunable(false); else { SVal V = state->getSVal(R); if (report.isInteresting(V)) event->setPrunable(false); } } return event; }
static bool hasViableCandidateToCall(clang::LookupResult& R, const cling::Value& V) { if (R.empty()) return false; using namespace clang; ASTContext& C = V.getASTContext(); Sema& SemaR = R.getSema(); OverloadCandidateSet overloads(SourceLocation(), OverloadCandidateSet::CSK_Normal); QualType Ty = V.getType().getNonReferenceType(); if (!Ty->isPointerType()) Ty = C.getPointerType(Ty); NamespaceDecl* ClingNSD = utils::Lookup::Namespace(&SemaR, "cling"); RecordDecl* ClingValueDecl = dyn_cast<RecordDecl>(utils::Lookup::Named(&SemaR, "Value", ClingNSD)); assert(ClingValueDecl && "Declaration must be found!"); QualType ClingValueTy = C.getTypeDeclType(ClingValueDecl); // The OverloadCandidateSet requires a QualType to be passed in through an // Expr* as part of Args. We know that we won't be using any node generated. // We need only an answer whether there is an overload taking these argument // types. We cannot afford to create useless Expr* on the AST for this // utility function which may be called thousands of times. Instead, we // create them on the stack and pretend they are on the heap. We get our // answer and forget about doing anything wrong. llvm::SmallVector<Expr, 4> exprsOnStack; SourceLocation noLoc; exprsOnStack.push_back(CXXNullPtrLiteralExpr(Ty, noLoc)); exprsOnStack.push_back(CXXNullPtrLiteralExpr(Ty, noLoc)); exprsOnStack.push_back(CXXNullPtrLiteralExpr(ClingValueTy, noLoc)); llvm::SmallVector<Expr*, 4> exprsFakedOnHeap; exprsFakedOnHeap.push_back(&exprsOnStack[0]); exprsFakedOnHeap.push_back(&exprsOnStack[1]); exprsFakedOnHeap.push_back(&exprsOnStack[2]); llvm::ArrayRef<Expr*> Args = llvm::makeArrayRef(exprsFakedOnHeap.data(), exprsFakedOnHeap.size()); // Could trigger deserialization of decls. cling::Interpreter::PushTransactionRAII RAII(V.getInterpreter()); SemaR.AddFunctionCandidates(R.asUnresolvedSet(), Args, overloads); OverloadCandidateSet::iterator Best; OverloadingResult OR = overloads.BestViableFunction(SemaR, SourceLocation(), Best); return OR == OR_Success; }
// CXXDeleteExpr QualType CXXDeleteExpr::getDestroyedType() const { const Expr *Arg = getArgument(); while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { if (ICE->getCastKind() != CK_UserDefinedConversion && ICE->getType()->isVoidPointerType()) Arg = ICE->getSubExpr(); else break; } // The type-to-delete may not be a pointer if it's a dependent type. const QualType ArgType = Arg->getType(); if (ArgType->isDependentType() && !ArgType->isPointerType()) return QualType(); return ArgType->getAs<PointerType>()->getPointeeType(); }
// We need to artificially create: // cling_PrintValue(void* (ASTContext)C, void* (Expr)E, const void* (&i) Expr* ValuePrinterSynthesizer::SynthesizeVP(Expr* E) { QualType QT = E->getType(); // For now we skip void and function pointer types. if (!QT.isNull() && (QT->isVoidType() || QT->isFunctionType())) return 0; // Find cling_PrintValue SourceLocation NoSLoc = SourceLocation(); DeclarationName PVName = &m_Context->Idents.get("cling_PrintValue"); LookupResult R(*m_Sema, PVName, NoSLoc, Sema::LookupOrdinaryName, Sema::ForRedeclaration); Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext); m_Sema->LookupName(R, S); assert(!R.empty() && "Cannot find cling_PrintValue(...)"); CXXScopeSpec CSS; Expr* UnresolvedLookup = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).take(); Expr* VoidEArg = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy, (uint64_t)E); Expr* VoidCArg = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy, (uint64_t)m_Context); if (!QT->isPointerType()) { while(ImplicitCastExpr* ICE = dyn_cast<ImplicitCastExpr>(E)) E = ICE->getSubExpr(); E = m_Sema->BuildUnaryOp(S, NoSLoc, UO_AddrOf, E).take(); } llvm::SmallVector<Expr*, 4> CallArgs; CallArgs.push_back(VoidEArg); CallArgs.push_back(VoidCArg); CallArgs.push_back(E); Expr* Result = m_Sema->ActOnCallExpr(S, UnresolvedLookup, NoSLoc, CallArgs, NoSLoc).take(); assert(Result && "Cannot create value printer!"); return Result; }
/// \brief If the member expression is operator-> (overloaded or not) on /// IndexVar, include it as a valid usage and prune the traversal. /// /// For example, given /// \code /// struct Foo { int bar(); int x; }; /// vector<Foo> v; /// \endcode /// the following uses will be considered convertible: /// \code /// for (vector<Foo>::iterator i = v.begin(), e = v.end(); i != e; ++i) { /// int b = i->bar(); /// int k = i->x + 1; /// } /// \endcode /// though /// \code /// for (vector<Foo>::iterator i = v.begin(), e = v.end(); i != e; ++i) { /// int k = i.insert(1); /// } /// for (vector<Foo>::iterator i = v.begin(), e = v.end(); i != e; ++i) { /// int b = e->bar(); /// } /// \endcode /// will not. bool ForLoopIndexUseVisitor::TraverseMemberExpr(MemberExpr *Member) { const Expr *Base = Member->getBase(); const DeclRefExpr *Obj = getDeclRef(Base); const Expr *ResultExpr = Member; QualType ExprType; if (const CXXOperatorCallExpr *Call = dyn_cast<CXXOperatorCallExpr>(Base->IgnoreParenImpCasts())) { // If operator->() is a MemberExpr containing a CXXOperatorCallExpr, then // the MemberExpr does not have the expression we want. We therefore catch // that instance here. // For example, if vector<Foo>::iterator defines operator->(), then the // example `i->bar()` at the top of this function is a CXXMemberCallExpr // referring to `i->` as the member function called. We want just `i`, so // we take the argument to operator->() as the base object. if(Call->getOperator() == OO_Arrow) { assert(Call->getNumArgs() == 1 && "Operator-> takes more than one argument"); Obj = getDeclRef(Call->getArg(0)); ResultExpr = Obj; ExprType = Call->getCallReturnType(); } } if (Member->isArrow() && Obj && exprReferencesVariable(IndexVar, Obj)) { if (ExprType.isNull()) ExprType = Obj->getType(); assert(ExprType->isPointerType() && "Operator-> returned non-pointer type"); // FIXME: This works around not having the location of the arrow operator. // Consider adding OperatorLoc to MemberExpr? SourceLocation ArrowLoc = Lexer::getLocForEndOfToken(Base->getExprLoc(), 0, Context->getSourceManager(), Context->getLangOpts()); // If something complicated is happening (i.e. the next token isn't an // arrow), give up on making this work. if (!ArrowLoc.isInvalid()) { Usages.push_back(Usage(ResultExpr, /*IsArrow=*/true, SourceRange(Base->getExprLoc(), ArrowLoc))); return true; } } return TraverseStmt(Member->getBase()); }
PathDiagnosticPiece * ConditionBRVisitor::VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr, const bool tookTrue, BugReporterContext &BRC, BugReport &report, const ExplodedNode *N) { // FIXME: If there's already a constraint tracker for this variable, // we shouldn't emit anything here (c.f. the double note in // test/Analysis/inlining/path-notes.c) SmallString<256> buf; llvm::raw_svector_ostream Out(buf); Out << "Assuming " << LhsString << " is "; QualType Ty = CondVarExpr->getType(); if (Ty->isPointerType()) Out << (tookTrue ? "not null" : "null"); else if (Ty->isObjCObjectPointerType()) Out << (tookTrue ? "not nil" : "nil"); else if (Ty->isBooleanType()) Out << (tookTrue ? "true" : "false"); else if (Ty->isIntegerType()) Out << (tookTrue ? "non-zero" : "zero"); else return 0; const LocationContext *LCtx = N->getLocationContext(); PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx); PathDiagnosticEventPiece *event = new PathDiagnosticEventPiece(Loc, Out.str()); if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(CondVarExpr)) { if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { const ProgramState *state = N->getState().getPtr(); if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { if (report.isInteresting(R)) event->setPrunable(false); } } } return event; }
// We need to artificially create: // cling_PrintValue(void* (ASTContext)C, void* (Expr)E, const void* (&i) Expr* ValuePrinterSynthesizer::SynthesizeVP(Expr* E) { QualType QT = E->getType(); // For now we skip void and function pointer types. if (!QT.isNull() && (QT->isVoidType() || QT->isFunctionType())) return 0; // Find cling_PrintValue if (!m_LookupResult) FindAndCacheRuntimeLookupResult(E->getLocStart()); Expr* VoidEArg = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy, (uint64_t)E); Expr* VoidCArg = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy, (uint64_t)m_Context); SourceLocation NoSLoc = SourceLocation(); Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext); if (!QT->isPointerType()) { while(ImplicitCastExpr* ICE = dyn_cast<ImplicitCastExpr>(E)) E = ICE->getSubExpr(); E = m_Sema->BuildUnaryOp(S, NoSLoc, UO_AddrOf, E).get(); } llvm::SmallVector<Expr*, 4> CallArgs; CallArgs.push_back(VoidEArg); CallArgs.push_back(VoidCArg); CallArgs.push_back(E); CXXScopeSpec CSS; Expr* unresolvedLookup = m_Sema->BuildDeclarationNameExpr(CSS, *m_LookupResult, /*ADL*/ false).get(); Expr* Result = m_Sema->ActOnCallExpr(S, unresolvedLookup, E->getLocStart(), CallArgs, E->getLocEnd()).get(); assert(Result && "Cannot create value printer!"); return Result; }
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. /// The result is of the given category. void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, CastExpr::CastKind Kind, ImplicitCastExpr::ResultCategory Category, const CXXCastPath *BasePath) { QualType ExprTy = Context.getCanonicalType(Expr->getType()); QualType TypeTy = Context.getCanonicalType(Ty); if (ExprTy == TypeTy) return; if (Expr->getType()->isPointerType() && Ty->isPointerType()) { QualType ExprBaseType = cast<PointerType>(ExprTy)->getPointeeType(); QualType BaseType = cast<PointerType>(TypeTy)->getPointeeType(); if (ExprBaseType.getAddressSpace() != BaseType.getAddressSpace()) { Diag(Expr->getExprLoc(), diag::err_implicit_pointer_address_space_cast) << Expr->getSourceRange(); } } // If this is a derived-to-base cast to a through a virtual base, we // need a vtable. if (Kind == CastExpr::CK_DerivedToBase && BasePathInvolvesVirtualBase(*BasePath)) { QualType T = Expr->getType(); if (const PointerType *Pointer = T->getAs<PointerType>()) T = Pointer->getPointeeType(); if (const RecordType *RecordTy = T->getAs<RecordType>()) MarkVTableUsed(Expr->getLocStart(), cast<CXXRecordDecl>(RecordTy->getDecl())); } if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { if (ImpCast->getCastKind() == Kind && (!BasePath || BasePath->empty())) { ImpCast->setType(Ty); ImpCast->setCategory(Category); return; } } Expr = ImplicitCastExpr::Create(Context, Ty, Kind, Expr, BasePath, Category); }
/// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in: /// @code ::delete ptr; @endcode /// or /// @code delete [] ptr; @endcode Action::OwningExprResult Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, ExprArg Operand) { // C++ 5.3.5p1: "The operand shall have a pointer type, or a class type // having a single conversion function to a pointer type. The result has // type void." // DR599 amends "pointer type" to "pointer to object type" in both cases. Expr *Ex = (Expr *)Operand.get(); if (!Ex->isTypeDependent()) { QualType Type = Ex->getType(); if (Type->isRecordType()) { // FIXME: Find that one conversion function and amend the type. } if (!Type->isPointerType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); QualType Pointee = Type->getAsPointerType()->getPointeeType(); if (Pointee->isFunctionType() || Pointee->isVoidType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex->getSourceRange()); else if (!Pointee->isDependentType() && RequireCompleteType(StartLoc, Pointee, diag::warn_delete_incomplete, Ex->getSourceRange())) return ExprError(); // FIXME: Look up the correct operator delete overload and pass a pointer // along. // FIXME: Check access and ambiguity of operator delete and destructor. } Operand.release(); return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, 0, Ex, StartLoc)); }
void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { // <type-encoding> ::= <storage-class> <variable-type> // <storage-class> ::= 0 # private static member // ::= 1 # protected static member // ::= 2 # public static member // ::= 3 # global // ::= 4 # static local // The first character in the encoding (after the name) is the storage class. if (VD->isStaticDataMember()) { // If it's a static member, it also encodes the access level. switch (VD->getAccess()) { default: case AS_private: Out << '0'; break; case AS_protected: Out << '1'; break; case AS_public: Out << '2'; break; } } else if (!VD->isStaticLocal()) Out << '3'; else Out << '4'; // Now mangle the type. // <variable-type> ::= <type> <cvr-qualifiers> // ::= <type> A # pointers, references, arrays // Pointers and references are odd. The type of 'int * const foo;' gets // mangled as 'QAHA' instead of 'PAHB', for example. QualType Ty = VD->getType(); if (Ty->isPointerType() || Ty->isReferenceType()) { mangleType(Ty); Out << 'A'; } else if (Ty->isArrayType()) { // Global arrays are funny, too. mangleType(cast<ArrayType>(Ty.getTypePtr()), true); Out << 'A'; } else { mangleType(Ty.getLocalUnqualifiedType()); mangleQualifiers(Ty.getLocalQualifiers(), false); } }