[clang] [clang] Implement -Walloc-size diagnostic option (PR #150028)
Vladimir Vuksanovic via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 6 02:38:36 PDT 2025
https://github.com/vvuksanovic updated https://github.com/llvm/llvm-project/pull/150028
>From 1f03a09bac08c70183d2a04fcbced83179cad414 Mon Sep 17 00:00:00 2001
From: Vladimir Vuksanovic <vladimir.vuksanovic at htecgroup.com>
Date: Mon, 7 Jul 2025 06:17:19 -0700
Subject: [PATCH 1/4] [clang] Implement -Walloc-size diagnostic option
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.
---
clang/docs/ReleaseNotes.rst | 4 ++
clang/include/clang/AST/Expr.h | 43 +++++++-----
.../clang/Basic/DiagnosticSemaKinds.td | 6 ++
clang/lib/AST/Expr.cpp | 53 +++++++++++++++
clang/lib/AST/ExprConstant.cpp | 66 +------------------
clang/lib/Sema/SemaExpr.cpp | 36 ++++++++++
clang/test/Sema/warn-alloc-size.c | 42 ++++++++++++
7 files changed, 170 insertions(+), 80 deletions(-)
create mode 100644 clang/test/Sema/warn-alloc-size.c
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 46a77673919d3..bf4615129f357 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -717,6 +717,10 @@ Improvements to Clang's diagnostics
Added a new warning in this group for the case where the attribute is missing/implicit on
an override of a virtual method.
+- A new warning ``-Walloc-size`` has been added to detect calls to functions
+ decorated with the ``alloc_size`` attribute don't allocate enough space for
+ the target pointer type.
+
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 523c0326d47ef..8bdd0d45dcbb1 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -40,23 +40,24 @@
#include <optional>
namespace clang {
- class APValue;
- class ASTContext;
- class BlockDecl;
- class CXXBaseSpecifier;
- class CXXMemberCallExpr;
- class CXXOperatorCallExpr;
- class CastExpr;
- class Decl;
- class IdentifierInfo;
- class MaterializeTemporaryExpr;
- class NamedDecl;
- class ObjCPropertyRefExpr;
- class OpaqueValueExpr;
- class ParmVarDecl;
- class StringLiteral;
- class TargetInfo;
- class ValueDecl;
+class AllocSizeAttr;
+class APValue;
+class ASTContext;
+class BlockDecl;
+class CXXBaseSpecifier;
+class CXXMemberCallExpr;
+class CXXOperatorCallExpr;
+class CastExpr;
+class Decl;
+class IdentifierInfo;
+class MaterializeTemporaryExpr;
+class NamedDecl;
+class ObjCPropertyRefExpr;
+class OpaqueValueExpr;
+class ParmVarDecl;
+class StringLiteral;
+class TargetInfo;
+class ValueDecl;
/// A simple array of base specifiers.
typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
@@ -3256,6 +3257,14 @@ class CallExpr : public Expr {
setDependence(getDependence() | ExprDependence::TypeValueInstantiation);
}
+ /// Try to get the alloc_size attribute of the callee. May return null.
+ const AllocSizeAttr *getAllocSizeAttr() const;
+
+ /// Get the total size in bytes allocated by calling a function decorated with
+ /// alloc_size. Returns true if the the result was successfully evaluated.
+ bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx,
+ llvm::APInt &Result) const;
+
bool isCallToStdMove() const;
static bool classof(const Stmt *T) {
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index b2ea65ae111be..67bd44f1e5dc4 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3684,6 +3684,12 @@ def warn_alloca_align_alignof : Warning<
"second argument to __builtin_alloca_with_align is supposed to be in bits">,
InGroup<DiagGroup<"alloca-with-align-alignof">>;
+def warn_alloc_size
+ : Warning<
+ "allocation of insufficient size '%0' for type %1 with size '%2'">,
+ InGroup<DiagGroup<"alloc-size">>,
+ DefaultIgnore;
+
def err_alignment_too_small : Error<
"requested alignment must be %0 or greater">;
def err_alignment_too_big : Error<
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 2e1a9a3d9ad63..eb5f5875fcc76 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3542,6 +3542,59 @@ bool CallExpr::isBuiltinAssumeFalse(const ASTContext &Ctx) const {
Arg->EvaluateAsBooleanCondition(ArgVal, Ctx) && !ArgVal;
}
+const AllocSizeAttr *CallExpr::getAllocSizeAttr() const {
+ if (const FunctionDecl *DirectCallee = getDirectCallee())
+ return DirectCallee->getAttr<AllocSizeAttr>();
+ if (const Decl *IndirectCallee = getCalleeDecl())
+ return IndirectCallee->getAttr<AllocSizeAttr>();
+ return nullptr;
+}
+
+bool CallExpr::getBytesReturnedByAllocSizeCall(const ASTContext &Ctx,
+ llvm::APInt &Result) const {
+ const AllocSizeAttr *AllocSize = getAllocSizeAttr();
+
+ assert(AllocSize && AllocSize->getElemSizeParam().isValid());
+ unsigned SizeArgNo = AllocSize->getElemSizeParam().getASTIndex();
+ unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType());
+ if (getNumArgs() <= SizeArgNo)
+ return false;
+
+ auto EvaluateAsSizeT = [&](const Expr *E, llvm::APSInt &Into) {
+ Expr::EvalResult ExprResult;
+ if (E->isValueDependent() ||
+ !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;
+ };
+
+ llvm::APSInt SizeOfElem;
+ if (!EvaluateAsSizeT(getArg(SizeArgNo), SizeOfElem))
+ return false;
+
+ if (!AllocSize->getNumElemsParam().isValid()) {
+ Result = std::move(SizeOfElem);
+ return true;
+ }
+
+ llvm::APSInt NumberOfElems;
+ unsigned NumArgNo = AllocSize->getNumElemsParam().getASTIndex();
+ if (!EvaluateAsSizeT(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;
+}
+
bool CallExpr::isCallToStdMove() const {
return getBuiltinCallee() == Builtin::BImove;
}
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 0d12161756467..a295d5e38b332 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->getAllocSizeAttr() ? CE : nullptr;
return nullptr;
}
@@ -9439,57 +9430,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,
@@ -9499,7 +9439,7 @@ 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);
+ return CE->getBytesReturnedByAllocSizeCall(Ctx, Result);
}
/// Attempts to evaluate the given LValueBase as the result of a call to
@@ -9977,7 +9917,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) {
if (ExprEvaluatorBaseTy::VisitCallExpr(E))
return true;
- if (!(InvalidBaseOK && getAllocSizeAttr(E)))
+ if (!(InvalidBaseOK && E->getAllocSizeAttr()))
return false;
Result.setInvalid(E);
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 45c7178c6965d..24088a7ca640c 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attrs.inc"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -7818,6 +7819,33 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
return prepareVectorSplat(DestTy, CastExpr);
}
+/// Check that a call to alloc_size function specifies sufficient space for the
+/// destination type.
+static void CheckSufficientAllocSize(Sema &S, QualType DestType,
+ const Expr *E) {
+ QualType SourceType = E->getType();
+ if (!DestType->isPointerType() || !SourceType->isPointerType() ||
+ DestType == SourceType)
+ return;
+
+ const auto *CE = dyn_cast<CallExpr>(E->IgnoreCasts());
+ if (!CE)
+ return;
+
+ // Find the total size allocated by the function call.
+ llvm::APInt AllocSize;
+ if (!CE->getAllocSizeAttr() ||
+ !CE->getBytesReturnedByAllocSizeCall(S.Context, AllocSize))
+ return;
+ auto Size = CharUnits::fromQuantity(AllocSize.getZExtValue());
+
+ QualType TargetType = DestType->getPointeeType();
+ auto LhsSize = S.Context.getTypeSizeInCharsIfKnown(TargetType);
+ if (LhsSize && Size < LhsSize)
+ S.Diag(E->getExprLoc(), diag::warn_alloc_size)
+ << Size.getQuantity() << TargetType << LhsSize->getQuantity();
+}
+
ExprResult
Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
Declarator &D, ParsedType &Ty,
@@ -7883,6 +7911,8 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
DiscardMisalignedMemberAddress(castType.getTypePtr(), CastExpr);
+ CheckSufficientAllocSize(*this, castType, CastExpr);
+
return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, CastExpr);
}
@@ -9887,6 +9917,12 @@ AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType LHSType,
AssignConvertType result =
CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS);
+ // If assigning a void * created by an allocation function call to some other
+ // type, check that the allocated size is sufficient for that type.
+ if (result != AssignConvertType::Incompatible &&
+ RHS.get()->getType()->isVoidPointerType())
+ CheckSufficientAllocSize(*this, LHSType, RHS.get());
+
// C99 6.5.16.1p2: The value of the right operand is converted to the
// type of the assignment expression.
// CheckAssignmentConstraints allows the left-hand side to be a reference,
diff --git a/clang/test/Sema/warn-alloc-size.c b/clang/test/Sema/warn-alloc-size.c
new file mode 100644
index 0000000000000..e1ce341b79678
--- /dev/null
+++ b/clang/test/Sema/warn-alloc-size.c
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Walloc-size %s
+struct Foo { int x[10]; };
+
+void *malloc(unsigned long) __attribute__((alloc_size(1)));
+void *alloca(unsigned long) __attribute__((alloc_size(1)));
+void *calloc(unsigned long, unsigned long) __attribute__((alloc_size(2, 1)));
+
+void foo_consumer(struct Foo* p);
+
+void alloc_foo(void) {
+ struct Foo *ptr1 = malloc(sizeof(struct Foo));
+ struct Foo *ptr2 = malloc(sizeof(*ptr2));
+ struct Foo *ptr3 = calloc(1, sizeof(*ptr3));
+ struct Foo *ptr4 = calloc(sizeof(*ptr4), 1);
+ struct Foo (*ptr5)[5] = malloc(sizeof(*ptr5));
+ void *ptr6 = malloc(4);
+
+ // Test insufficient size with different allocation functions.
+ struct Foo *ptr7 = malloc(sizeof(ptr7)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
+ struct Foo *ptr8 = alloca(sizeof(ptr8)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
+ struct Foo *ptr9 = calloc(1, sizeof(ptr9)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
+ struct Foo *ptr10 = calloc(sizeof(ptr10), 1); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
+
+ // Test function arguments.
+ foo_consumer(malloc(4)); // expected-warning {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
+
+ // Test explicit cast.
+ struct Foo *ptr11 = (struct Foo *)malloc(sizeof(*ptr11));
+ struct Foo *ptr12 = (struct Foo *)malloc(sizeof(ptr12)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
+ struct Foo *ptr13 = (struct Foo *)alloca(sizeof(ptr13)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
+ struct Foo *ptr14 = (struct Foo *)calloc(1, sizeof(ptr14)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
+ struct Foo *ptr15 = (struct Foo *)malloc(4); // expected-warning {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
+ void *ptr16 = (struct Foo *)malloc(4); // expected-warning {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
+
+ struct Foo *ptr17 = (void *)(struct Foo *)malloc(4); // expected-warning 2 {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
+ int *ptr18 = (unsigned *)(void *)(int *)malloc(1); // expected-warning {{initializing 'int *' with an expression of type 'unsigned int *' converts between pointers to integer types with different sign}}
+ // expected-warning at -1 {{allocation of insufficient size '1' for type 'int' with size '4'}}
+ // expected-warning at -2 {{allocation of insufficient size '1' for type 'unsigned int' with size '4'}}
+ int *ptr19 = (void *)(int *)malloc(1); // expected-warning {{allocation of insufficient size '1' for type 'int' with size '4'}}
+ // expected-warning at -1 {{allocation of insufficient size '1' for type 'int' with size '4'}}
+ (void)(int *)malloc(1); // expected-warning {{allocation of insufficient size '1' for type 'int' with size '4'}}
+}
>From c483fd3b51530ab2a0e5b9d57542232bdfe8bdaa Mon Sep 17 00:00:00 2001
From: Vladimir Vuksanovic <vvuksano at cisco.com>
Date: Mon, 28 Jul 2025 06:43:05 -0700
Subject: [PATCH 2/4] Address comments and issues
---
clang/include/clang/AST/Expr.h | 8 ++---
clang/include/clang/Basic/AttrDocs.td | 14 ++++++++
clang/lib/AST/Expr.cpp | 25 +++++++--------
clang/lib/AST/ExprConstant.cpp | 11 +++++--
clang/lib/Sema/SemaExpr.cpp | 10 +++---
clang/test/Sema/warn-alloc-size.c | 46 +++++++++++++--------------
6 files changed, 65 insertions(+), 49 deletions(-)
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 8bdd0d45dcbb1..1e320a305a949 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -3258,12 +3258,12 @@ class CallExpr : public Expr {
}
/// Try to get the alloc_size attribute of the callee. May return null.
- const AllocSizeAttr *getAllocSizeAttr() const;
+ const AllocSizeAttr *getCalleeAllocSizeAttr() const;
/// Get the total size in bytes allocated by calling a function decorated with
- /// alloc_size. Returns true if the the result was successfully evaluated.
- bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx,
- llvm::APInt &Result) const;
+ /// alloc_size. Returns std::nullopt if the the result cannot be evaluated.
+ std::optional<llvm::APInt>
+ getBytesReturnedByAllocSizeCall(const ASTContext &Ctx) const;
bool isCallToStdMove() const;
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index fefdaba7f8bf5..967bee715d7ee 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -932,6 +932,20 @@ An example of how to use ``alloc_size``
assert(__builtin_object_size(a, 0) == 100);
}
+When ``-Walloc-size`` is enabled, this attribute allows the compiler to
+diagnose cases when the allocated memory is insufficient for the size of the
+type the returned pointer is cast to.
+
+.. code-block:: c
+
+ void *my_malloc(int a) __attribute__((alloc_size(1)));
+ void consumer_func(int *);
+
+ int main() {
+ int *w = my_malloc(1); // warning: allocation of insufficient size '1' for type 'int' with size '4'
+ consumer_func(my_malloc(1)); // warning: allocation of insufficient size '1' for type 'int' with size '4'
+ }
+
.. Note:: This attribute works differently in clang than it does in GCC.
Specifically, clang will only trace ``const`` pointers (as above); we give up
on pointers that are not marked as ``const``. In the vast majority of cases,
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index eb5f5875fcc76..43d32f4fcd472 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3542,7 +3542,7 @@ bool CallExpr::isBuiltinAssumeFalse(const ASTContext &Ctx) const {
Arg->EvaluateAsBooleanCondition(ArgVal, Ctx) && !ArgVal;
}
-const AllocSizeAttr *CallExpr::getAllocSizeAttr() const {
+const AllocSizeAttr *CallExpr::getCalleeAllocSizeAttr() const {
if (const FunctionDecl *DirectCallee = getDirectCallee())
return DirectCallee->getAttr<AllocSizeAttr>();
if (const Decl *IndirectCallee = getCalleeDecl())
@@ -3550,15 +3550,15 @@ const AllocSizeAttr *CallExpr::getAllocSizeAttr() const {
return nullptr;
}
-bool CallExpr::getBytesReturnedByAllocSizeCall(const ASTContext &Ctx,
- llvm::APInt &Result) const {
- const AllocSizeAttr *AllocSize = getAllocSizeAttr();
+std::optional<llvm::APInt>
+CallExpr::getBytesReturnedByAllocSizeCall(const ASTContext &Ctx) const {
+ const AllocSizeAttr *AllocSize = getCalleeAllocSizeAttr();
assert(AllocSize && AllocSize->getElemSizeParam().isValid());
unsigned SizeArgNo = AllocSize->getElemSizeParam().getASTIndex();
unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType());
if (getNumArgs() <= SizeArgNo)
- return false;
+ return {};
auto EvaluateAsSizeT = [&](const Expr *E, llvm::APSInt &Into) {
Expr::EvalResult ExprResult;
@@ -3574,25 +3574,22 @@ bool CallExpr::getBytesReturnedByAllocSizeCall(const ASTContext &Ctx,
llvm::APSInt SizeOfElem;
if (!EvaluateAsSizeT(getArg(SizeArgNo), SizeOfElem))
- return false;
+ return {};
- if (!AllocSize->getNumElemsParam().isValid()) {
- Result = std::move(SizeOfElem);
- return true;
- }
+ if (!AllocSize->getNumElemsParam().isValid())
+ return SizeOfElem;
llvm::APSInt NumberOfElems;
unsigned NumArgNo = AllocSize->getNumElemsParam().getASTIndex();
if (!EvaluateAsSizeT(getArg(NumArgNo), NumberOfElems))
- return false;
+ return {};
bool Overflow;
llvm::APInt BytesAvailable = SizeOfElem.umul_ov(NumberOfElems, Overflow);
if (Overflow)
- return false;
+ return {};
- Result = std::move(BytesAvailable);
- return true;
+ return BytesAvailable;
}
bool CallExpr::isCallToStdMove() const {
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index a295d5e38b332..de295ef6545d1 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -133,7 +133,7 @@ namespace {
E = Cast->getSubExpr()->IgnoreParens();
if (const auto *CE = dyn_cast<CallExpr>(E))
- return CE->getAllocSizeAttr() ? CE : nullptr;
+ return CE->getCalleeAllocSizeAttr() ? CE : nullptr;
return nullptr;
}
@@ -9439,7 +9439,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 CE->getBytesReturnedByAllocSizeCall(Ctx, 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
@@ -9917,7 +9922,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) {
if (ExprEvaluatorBaseTy::VisitCallExpr(E))
return true;
- if (!(InvalidBaseOK && E->getAllocSizeAttr()))
+ if (!(InvalidBaseOK && E->getCalleeAllocSizeAttr()))
return false;
Result.setInvalid(E);
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 24088a7ca640c..8c31168c6eeed 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7833,11 +7833,13 @@ static void CheckSufficientAllocSize(Sema &S, QualType DestType,
return;
// Find the total size allocated by the function call.
- llvm::APInt AllocSize;
- if (!CE->getAllocSizeAttr() ||
- !CE->getBytesReturnedByAllocSizeCall(S.Context, AllocSize))
+ if (!CE->getCalleeAllocSizeAttr())
return;
- auto Size = CharUnits::fromQuantity(AllocSize.getZExtValue());
+ std::optional<llvm::APInt> AllocSize =
+ CE->getBytesReturnedByAllocSizeCall(S.Context);
+ if (!AllocSize)
+ return;
+ auto Size = CharUnits::fromQuantity(AllocSize->getZExtValue());
QualType TargetType = DestType->getPointeeType();
auto LhsSize = S.Context.getTypeSizeInCharsIfKnown(TargetType);
diff --git a/clang/test/Sema/warn-alloc-size.c b/clang/test/Sema/warn-alloc-size.c
index e1ce341b79678..3cdfb5c0d4b4f 100644
--- a/clang/test/Sema/warn-alloc-size.c
+++ b/clang/test/Sema/warn-alloc-size.c
@@ -1,42 +1,40 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Walloc-size %s
struct Foo { int x[10]; };
-void *malloc(unsigned long) __attribute__((alloc_size(1)));
-void *alloca(unsigned long) __attribute__((alloc_size(1)));
-void *calloc(unsigned long, unsigned long) __attribute__((alloc_size(2, 1)));
+typedef __typeof__(sizeof(int)) size_t;
+void *my_malloc(size_t) __attribute__((alloc_size(1)));
+void *my_calloc(size_t, size_t) __attribute__((alloc_size(2, 1)));
void foo_consumer(struct Foo* p);
void alloc_foo(void) {
- struct Foo *ptr1 = malloc(sizeof(struct Foo));
- struct Foo *ptr2 = malloc(sizeof(*ptr2));
- struct Foo *ptr3 = calloc(1, sizeof(*ptr3));
- struct Foo *ptr4 = calloc(sizeof(*ptr4), 1);
- struct Foo (*ptr5)[5] = malloc(sizeof(*ptr5));
- void *ptr6 = malloc(4);
+ struct Foo *ptr1 = my_malloc(sizeof(struct Foo));
+ struct Foo *ptr2 = my_malloc(sizeof(*ptr2));
+ struct Foo *ptr3 = my_calloc(1, sizeof(*ptr3));
+ struct Foo *ptr4 = my_calloc(sizeof(*ptr4), 1);
+ struct Foo (*ptr5)[5] = my_malloc(sizeof(*ptr5));
+ void *ptr6 = my_malloc(4);
// Test insufficient size with different allocation functions.
- struct Foo *ptr7 = malloc(sizeof(ptr7)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
- struct Foo *ptr8 = alloca(sizeof(ptr8)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
- struct Foo *ptr9 = calloc(1, sizeof(ptr9)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
- struct Foo *ptr10 = calloc(sizeof(ptr10), 1); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
+ struct Foo *ptr7 = my_malloc(sizeof(ptr7)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
+ struct Foo *ptr8 = my_calloc(1, sizeof(ptr8)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
+ struct Foo *ptr9 = my_calloc(sizeof(ptr9), 1); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
// Test function arguments.
- foo_consumer(malloc(4)); // expected-warning {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
+ foo_consumer(my_malloc(4)); // expected-warning {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
// Test explicit cast.
- struct Foo *ptr11 = (struct Foo *)malloc(sizeof(*ptr11));
- struct Foo *ptr12 = (struct Foo *)malloc(sizeof(ptr12)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
- struct Foo *ptr13 = (struct Foo *)alloca(sizeof(ptr13)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
- struct Foo *ptr14 = (struct Foo *)calloc(1, sizeof(ptr14)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
- struct Foo *ptr15 = (struct Foo *)malloc(4); // expected-warning {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
- void *ptr16 = (struct Foo *)malloc(4); // expected-warning {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
+ struct Foo *ptr10 = (struct Foo *)my_malloc(sizeof(*ptr10));
+ struct Foo *ptr11 = (struct Foo *)my_malloc(sizeof(ptr11)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
+ struct Foo *ptr12 = (struct Foo *)my_calloc(1, sizeof(ptr12)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
+ struct Foo *ptr13 = (struct Foo *)my_malloc(4); // expected-warning {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
+ void *ptr14 = (struct Foo *)my_malloc(4); // expected-warning {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
- struct Foo *ptr17 = (void *)(struct Foo *)malloc(4); // expected-warning 2 {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
- int *ptr18 = (unsigned *)(void *)(int *)malloc(1); // expected-warning {{initializing 'int *' with an expression of type 'unsigned int *' converts between pointers to integer types with different sign}}
+ struct Foo *ptr15 = (void *)(struct Foo *)my_malloc(4); // expected-warning 2 {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
+ int *ptr16 = (unsigned *)(void *)(int *)my_malloc(1); // expected-warning {{initializing 'int *' with an expression of type 'unsigned int *' converts between pointers to integer types with different sign}}
// expected-warning at -1 {{allocation of insufficient size '1' for type 'int' with size '4'}}
// expected-warning at -2 {{allocation of insufficient size '1' for type 'unsigned int' with size '4'}}
- int *ptr19 = (void *)(int *)malloc(1); // expected-warning {{allocation of insufficient size '1' for type 'int' with size '4'}}
+ int *ptr17 = (void *)(int *)my_malloc(1); // expected-warning {{allocation of insufficient size '1' for type 'int' with size '4'}}
// expected-warning at -1 {{allocation of insufficient size '1' for type 'int' with size '4'}}
- (void)(int *)malloc(1); // expected-warning {{allocation of insufficient size '1' for type 'int' with size '4'}}
+ (void)(int *)my_malloc(1); // expected-warning {{allocation of insufficient size '1' for type 'int' with size '4'}}
}
>From c790ac1660aea69a5a091fad7aa03b2e2d934dfb Mon Sep 17 00:00:00 2001
From: Vladimir Vuksanovic <vvuksano at cisco.com>
Date: Mon, 28 Jul 2025 06:43:25 -0700
Subject: [PATCH 3/4] Make -Walloc-size enabled by default
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 +--
.../Malloc+MismatchedDeallocator+NewDelete.cpp | 4 ++--
.../Malloc+MismatchedDeallocator_intersections.cpp | 2 +-
.../Analysis/MismatchedDeallocator-checker-test.mm | 4 ++--
clang/test/Analysis/NewDelete-checker-test.cpp | 6 ++++++
clang/test/Analysis/NewDelete-intersections.mm | 3 +++
clang/test/Analysis/castsize.c | 2 +-
clang/test/Analysis/malloc-annotations.c | 1 +
clang/test/Analysis/malloc-sizeof.c | 2 +-
clang/test/Analysis/malloc.c | 1 +
clang/test/Analysis/unix-fns.c | 4 ++--
clang/test/Sema/implicit-void-ptr-cast.c | 10 +++++-----
12 files changed, 26 insertions(+), 16 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 67bd44f1e5dc4..6732dc891a5e0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3687,8 +3687,7 @@ def warn_alloca_align_alignof : Warning<
def warn_alloc_size
: Warning<
"allocation of insufficient size '%0' for type %1 with size '%2'">,
- InGroup<DiagGroup<"alloc-size">>,
- DefaultIgnore;
+ InGroup<DiagGroup<"alloc-size">>;
def err_alignment_too_small : Error<
"requested alignment must be %0 or greater">;
diff --git a/clang/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp b/clang/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
index 6c20b4ba53dae..512dacc97945e 100644
--- a/clang/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
+++ b/clang/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete -std=c++11 -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -Wno-alloc-size -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -Wno-alloc-size -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,cplusplus.NewDelete,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -verify %s
#include "Inputs/system-header-simulator-for-malloc.h"
diff --git a/clang/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp b/clang/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
index b0cef2591486d..98873409a4fa2 100644
--- a/clang/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
+++ b/clang/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -Wno-alloc-size -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator -std=c++11 -verify %s
// expected-no-diagnostics
typedef __typeof(sizeof(int)) size_t;
diff --git a/clang/test/Analysis/MismatchedDeallocator-checker-test.mm b/clang/test/Analysis/MismatchedDeallocator-checker-test.mm
index ef8b24ba8de32..21cbe86c9726f 100644
--- a/clang/test/Analysis/MismatchedDeallocator-checker-test.mm
+++ b/clang/test/Analysis/MismatchedDeallocator-checker-test.mm
@@ -1,5 +1,5 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.MismatchedDeallocator -fblocks -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.MismatchedDeallocator -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
+// RUN: %clang_analyze_cc1 -Wno-alloc-size -analyzer-checker=core,unix.MismatchedDeallocator -fblocks -verify %s
+// RUN: %clang_analyze_cc1 -Wno-alloc-size -analyzer-checker=core,unix.MismatchedDeallocator -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
#include "Inputs/system-header-simulator-objc.h"
#include "Inputs/system-header-simulator-cxx.h"
diff --git a/clang/test/Analysis/NewDelete-checker-test.cpp b/clang/test/Analysis/NewDelete-checker-test.cpp
index 7c3e142d586bb..a4d7d131b26e5 100644
--- a/clang/test/Analysis/NewDelete-checker-test.cpp
+++ b/clang/test/Analysis/NewDelete-checker-test.cpp
@@ -1,31 +1,37 @@
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks %s \
+// RUN: -Wno-alloc-size \
// RUN: -verify=expected,newdelete \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDelete
//
// RUN: %clang_analyze_cc1 -DLEAKS -std=c++11 -fblocks %s \
+// RUN: -Wno-alloc-size \
// RUN: -verify=expected,newdelete,leak \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDelete \
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks
//
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -verify %s \
+// RUN: -Wno-alloc-size \
// RUN: -verify=expected,leak \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks
//
// RUN: %clang_analyze_cc1 -std=c++17 -fblocks %s \
+// RUN: -Wno-alloc-size \
// RUN: -verify=expected,newdelete \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDelete
//
// RUN: %clang_analyze_cc1 -DLEAKS -std=c++17 -fblocks %s \
+// RUN: -Wno-alloc-size \
// RUN: -verify=expected,newdelete,leak \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDelete \
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks
//
// RUN: %clang_analyze_cc1 -std=c++17 -fblocks -verify %s \
+// RUN: -Wno-alloc-size \
// RUN: -verify=expected,leak,inspection \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks \
diff --git a/clang/test/Analysis/NewDelete-intersections.mm b/clang/test/Analysis/NewDelete-intersections.mm
index e897f48b83962..c1726b5bd5e8d 100644
--- a/clang/test/Analysis/NewDelete-intersections.mm
+++ b/clang/test/Analysis/NewDelete-intersections.mm
@@ -1,4 +1,5 @@
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks %s \
+// RUN: -Wno-alloc-size \
// RUN: -verify=newdelete \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDelete
@@ -6,11 +7,13 @@
// leak-no-diagnostics
// RUN: %clang_analyze_cc1 -std=c++11 -DLEAKS -fblocks %s \
+// RUN: -Wno-alloc-size \
// RUN: -verify=leak \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks
// RUN: %clang_analyze_cc1 -std=c++11 -DLEAKS -fblocks %s \
+// RUN: -Wno-alloc-size \
// RUN: -verify=mismatch \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=unix.MismatchedDeallocator
diff --git a/clang/test/Analysis/castsize.c b/clang/test/Analysis/castsize.c
index 81aa60c0414cd..b08203bdc2254 100644
--- a/clang/test/Analysis/castsize.c
+++ b/clang/test/Analysis/castsize.c
@@ -1,5 +1,5 @@
// RUN: %clang_analyze_cc1 -verify %s \
-// RUN: -analyzer-checker=core,unix.Malloc,alpha.core.CastSize
+// RUN: -Wno-alloc-size -analyzer-checker=core,unix.Malloc,alpha.core.CastSize
typedef typeof(sizeof(int)) size_t;
void *malloc(size_t);
diff --git a/clang/test/Analysis/malloc-annotations.c b/clang/test/Analysis/malloc-annotations.c
index 3a8b1b2842d07..b5696dd8495f8 100644
--- a/clang/test/Analysis/malloc-annotations.c
+++ b/clang/test/Analysis/malloc-annotations.c
@@ -1,4 +1,5 @@
// RUN: %clang_analyze_cc1 -verify \
+// RUN: -Wno-alloc-size \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=alpha.deadcode.UnreachableCode \
// RUN: -analyzer-checker=alpha.core.CastSize \
diff --git a/clang/test/Analysis/malloc-sizeof.c b/clang/test/Analysis/malloc-sizeof.c
index 4573c193881e3..6202795bc1005 100644
--- a/clang/test/Analysis/malloc-sizeof.c
+++ b/clang/test/Analysis/malloc-sizeof.c
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=unix.MallocSizeof -verify %s
+// RUN: %clang_analyze_cc1 -Wno-alloc-size -analyzer-checker=unix.MallocSizeof -verify %s
#include <stddef.h>
diff --git a/clang/test/Analysis/malloc.c b/clang/test/Analysis/malloc.c
index 27a04ff873521..1bd8c034ee7de 100644
--- a/clang/test/Analysis/malloc.c
+++ b/clang/test/Analysis/malloc.c
@@ -1,4 +1,5 @@
// RUN: %clang_analyze_cc1 -Wno-strict-prototypes -Wno-error=implicit-int -verify %s \
+// RUN: -Wno-alloc-size \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=alpha.deadcode.UnreachableCode \
// RUN: -analyzer-checker=alpha.core.CastSize \
diff --git a/clang/test/Analysis/unix-fns.c b/clang/test/Analysis/unix-fns.c
index 77894285bcb69..2a971be2e6023 100644
--- a/clang/test/Analysis/unix-fns.c
+++ b/clang/test/Analysis/unix-fns.c
@@ -1,6 +1,6 @@
-// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,unix.API,osx.API,optin.portability %s -analyzer-output=plist -analyzer-config faux-bodies=true -fblocks -verify -o %t.plist
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -Wno-alloc-size -analyzer-checker=core,unix.API,osx.API,optin.portability %s -analyzer-output=plist -analyzer-config faux-bodies=true -fblocks -verify -o %t.plist
// RUN: %normalize_plist <%t.plist | diff -ub %S/Inputs/expected-plists/unix-fns.c.plist -
-// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -analyzer-checker=core,unix.API,osx.API,optin.portability %s -analyzer-output=plist -analyzer-config faux-bodies=true -fblocks -verify -o %t.plist
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -Wno-alloc-size -analyzer-checker=core,unix.API,osx.API,optin.portability %s -analyzer-output=plist -analyzer-config faux-bodies=true -fblocks -verify -o %t.plist
// RUN: %normalize_plist <%t.plist | diff -ub %S/Inputs/expected-plists/unix-fns.c.plist -
// RUN: mkdir -p %t.dir
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.API,osx.API,optin.portability -analyzer-output=html -analyzer-config faux-bodies=true -fblocks -o %t.dir %s
diff --git a/clang/test/Sema/implicit-void-ptr-cast.c b/clang/test/Sema/implicit-void-ptr-cast.c
index 3c3e153d1dbda..e8f193b22f935 100644
--- a/clang/test/Sema/implicit-void-ptr-cast.c
+++ b/clang/test/Sema/implicit-void-ptr-cast.c
@@ -1,8 +1,8 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify=c -Wimplicit-void-ptr-cast %s
-// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify=c -Wc++-compat %s
-// RUN: %clang_cc1 -fsyntax-only -verify=cxx -x c++ %s
-// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify=good %s
-// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify=good -Wc++-compat -Wno-implicit-void-ptr-cast %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-alloc-size -std=c23 -verify=c -Wimplicit-void-ptr-cast %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-alloc-size -std=c23 -verify=c -Wc++-compat %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-alloc-size -verify=cxx -x c++ %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-alloc-size -std=c23 -verify=good %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-alloc-size -std=c23 -verify=good -Wc++-compat -Wno-implicit-void-ptr-cast %s
// good-no-diagnostics
typedef __typeof__(sizeof(int)) size_t;
>From aa57034ecb243d7eacd5673854bd32cb3bf07e33 Mon Sep 17 00:00:00 2001
From: Vladimir Vuksanovic <vladimir.vuksanovic at htecgroup.com>
Date: Tue, 5 Aug 2025 12:00:07 +0200
Subject: [PATCH 4/4] Address comments
---
clang/include/clang/Basic/AttrDocs.td | 1 +
clang/lib/Sema/SemaExpr.cpp | 2 +-
clang/test/Sema/warn-alloc-size.c | 15 +++++++++++----
3 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 967bee715d7ee..3eb387fa72ea8 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -942,6 +942,7 @@ type the returned pointer is cast to.
void consumer_func(int *);
int main() {
+ int *ptr = my_malloc(sizeof(int)); // no warning
int *w = my_malloc(1); // warning: allocation of insufficient size '1' for type 'int' with size '4'
consumer_func(my_malloc(1)); // warning: allocation of insufficient size '1' for type 'int' with size '4'
}
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 8c31168c6eeed..f9edd24739ae4 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7828,7 +7828,7 @@ static void CheckSufficientAllocSize(Sema &S, QualType DestType,
DestType == SourceType)
return;
- const auto *CE = dyn_cast<CallExpr>(E->IgnoreCasts());
+ const auto *CE = dyn_cast<CallExpr>(E->IgnoreParenCasts());
if (!CE)
return;
diff --git a/clang/test/Sema/warn-alloc-size.c b/clang/test/Sema/warn-alloc-size.c
index 3cdfb5c0d4b4f..038342606fe0c 100644
--- a/clang/test/Sema/warn-alloc-size.c
+++ b/clang/test/Sema/warn-alloc-size.c
@@ -1,6 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Walloc-size %s
struct Foo { int x[10]; };
+struct ZeroSize {
+ int flexible_array[];
+};
+
typedef __typeof__(sizeof(int)) size_t;
void *my_malloc(size_t) __attribute__((alloc_size(1)));
void *my_calloc(size_t, size_t) __attribute__((alloc_size(2, 1)));
@@ -18,7 +22,7 @@ void alloc_foo(void) {
// Test insufficient size with different allocation functions.
struct Foo *ptr7 = my_malloc(sizeof(ptr7)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
struct Foo *ptr8 = my_calloc(1, sizeof(ptr8)); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
- struct Foo *ptr9 = my_calloc(sizeof(ptr9), 1); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
+ struct Foo *ptr9 = my_calloc(sizeof(ptr9), 1); // expected-warning {{allocation of insufficient size '8' for type 'struct Foo' with size '40'}}
// Test function arguments.
foo_consumer(my_malloc(4)); // expected-warning {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
@@ -32,9 +36,12 @@ void alloc_foo(void) {
struct Foo *ptr15 = (void *)(struct Foo *)my_malloc(4); // expected-warning 2 {{allocation of insufficient size '4' for type 'struct Foo' with size '40'}}
int *ptr16 = (unsigned *)(void *)(int *)my_malloc(1); // expected-warning {{initializing 'int *' with an expression of type 'unsigned int *' converts between pointers to integer types with different sign}}
- // expected-warning at -1 {{allocation of insufficient size '1' for type 'int' with size '4'}}
- // expected-warning at -2 {{allocation of insufficient size '1' for type 'unsigned int' with size '4'}}
+ // expected-warning at -1 {{allocation of insufficient size '1' for type 'int' with size '4'}}
+ // expected-warning at -2 {{allocation of insufficient size '1' for type 'unsigned int' with size '4'}}
int *ptr17 = (void *)(int *)my_malloc(1); // expected-warning {{allocation of insufficient size '1' for type 'int' with size '4'}}
- // expected-warning at -1 {{allocation of insufficient size '1' for type 'int' with size '4'}}
+ // expected-warning at -1 {{allocation of insufficient size '1' for type 'int' with size '4'}}
(void)(int *)my_malloc(1); // expected-warning {{allocation of insufficient size '1' for type 'int' with size '4'}}
+
+ struct ZeroSize *ptr18 = my_malloc(0); // okay becuase sizeof(struct ZeroSize) = 0
+ // allocation of size 0 is implementation defined behavior though
}
More information about the cfe-commits
mailing list