diff options
author | Vladimir Vuksanovic <109677816+vvuksanovic@users.noreply.github.com> | 2025-08-25 16:46:08 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-08-25 07:46:08 -0700 |
commit | 6dc188d4eb15cbe9bdece3d940f03d93b926328c (patch) | |
tree | 48d497a7d6065f9d36067eb5f6da86ba2d2ac5c8 /clang/lib/AST/ExprConstant.cpp | |
parent | 495adb3aa392f113c57987aef341125450d13c53 (diff) | |
download | llvm-6dc188d4eb15cbe9bdece3d940f03d93b926328c.zip llvm-6dc188d4eb15cbe9bdece3d940f03d93b926328c.tar.gz llvm-6dc188d4eb15cbe9bdece3d940f03d93b926328c.tar.bz2 |
[clang] Implement -Walloc-size diagnostic option (#150028)
Warns about calls to functions decorated with attribute `alloc_size`
that specify insufficient size for the type they are cast to. Matches
the behavior of the GCC option of the same name.
Closes #138973
---------
Co-authored-by: Vladimir Vuksanovic <vvuksano@cisco.com>
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 71 |
1 files changed, 8 insertions, 63 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index a71cb8b..2c8e9e5 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -114,15 +114,6 @@ namespace { return Ctx.getLValueReferenceType(E->getType()); } - /// Given a CallExpr, try to get the alloc_size attribute. May return null. - static const AllocSizeAttr *getAllocSizeAttr(const CallExpr *CE) { - if (const FunctionDecl *DirectCallee = CE->getDirectCallee()) - return DirectCallee->getAttr<AllocSizeAttr>(); - if (const Decl *IndirectCallee = CE->getCalleeDecl()) - return IndirectCallee->getAttr<AllocSizeAttr>(); - return nullptr; - } - /// Attempts to unwrap a CallExpr (with an alloc_size attribute) from an Expr. /// This will look through a single cast. /// @@ -142,7 +133,7 @@ namespace { E = Cast->getSubExpr()->IgnoreParens(); if (const auto *CE = dyn_cast<CallExpr>(E)) - return getAllocSizeAttr(CE) ? CE : nullptr; + return CE->getCalleeAllocSizeAttr() ? CE : nullptr; return nullptr; } @@ -9466,57 +9457,6 @@ bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) { // Pointer Evaluation //===----------------------------------------------------------------------===// -/// Attempts to compute the number of bytes available at the pointer -/// returned by a function with the alloc_size attribute. Returns true if we -/// were successful. Places an unsigned number into `Result`. -/// -/// This expects the given CallExpr to be a call to a function with an -/// alloc_size attribute. -static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, - const CallExpr *Call, - llvm::APInt &Result) { - const AllocSizeAttr *AllocSize = getAllocSizeAttr(Call); - - assert(AllocSize && AllocSize->getElemSizeParam().isValid()); - unsigned SizeArgNo = AllocSize->getElemSizeParam().getASTIndex(); - unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType()); - if (Call->getNumArgs() <= SizeArgNo) - return false; - - auto EvaluateAsSizeT = [&](const Expr *E, APSInt &Into) { - Expr::EvalResult ExprResult; - if (!E->EvaluateAsInt(ExprResult, Ctx, Expr::SE_AllowSideEffects)) - return false; - Into = ExprResult.Val.getInt(); - if (Into.isNegative() || !Into.isIntN(BitsInSizeT)) - return false; - Into = Into.zext(BitsInSizeT); - return true; - }; - - APSInt SizeOfElem; - if (!EvaluateAsSizeT(Call->getArg(SizeArgNo), SizeOfElem)) - return false; - - if (!AllocSize->getNumElemsParam().isValid()) { - Result = std::move(SizeOfElem); - return true; - } - - APSInt NumberOfElems; - unsigned NumArgNo = AllocSize->getNumElemsParam().getASTIndex(); - if (!EvaluateAsSizeT(Call->getArg(NumArgNo), NumberOfElems)) - return false; - - bool Overflow; - llvm::APInt BytesAvailable = SizeOfElem.umul_ov(NumberOfElems, Overflow); - if (Overflow) - return false; - - Result = std::move(BytesAvailable); - return true; -} - /// Convenience function. LVal's base must be a call to an alloc_size /// function. static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, @@ -9526,7 +9466,12 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, "Can't get the size of a non alloc_size function"); const auto *Base = LVal.getLValueBase().get<const Expr *>(); const CallExpr *CE = tryUnwrapAllocSizeCall(Base); - return getBytesReturnedByAllocSizeCall(Ctx, CE, Result); + std::optional<llvm::APInt> Size = CE->getBytesReturnedByAllocSizeCall(Ctx); + if (!Size) + return false; + + Result = std::move(*Size); + return true; } /// Attempts to evaluate the given LValueBase as the result of a call to @@ -10017,7 +9962,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) { if (ExprEvaluatorBaseTy::VisitCallExpr(E)) return true; - if (!(InvalidBaseOK && getAllocSizeAttr(E))) + if (!(InvalidBaseOK && E->getCalleeAllocSizeAttr())) return false; Result.setInvalid(E); |