Author: Marco Elver
Date: 2025-10-09T09:31:16+02:00
New Revision: dfa8732d050dea1fd213c7a68a17501febc80794

URL: 
https://github.com/llvm/llvm-project/commit/dfa8732d050dea1fd213c7a68a17501febc80794
DIFF: 
https://github.com/llvm/llvm-project/commit/dfa8732d050dea1fd213c7a68a17501febc80794.diff

LOG: [AllocToken, Clang] Infer type hints from sizeof expressions and casts 
(#156841)

For the AllocToken pass to accurately calculate token ID hints, we
need to attach `!alloc_token` metadata for allocation calls.

Unlike new expressions, untyped allocation calls (like `malloc`,
`calloc`, `::operator new(..)`, `__builtin_operator_new`, etc.) have no
syntactic type associated with them. For -fsanitize=alloc-token, type
hints are sufficient, and we can attempt to infer the type based on
common idioms.

When encountering allocation calls (with `__attribute__((malloc))` or
`__attribute__((alloc_size(..))`), attach `!alloc_token` by inferring
the allocated type from (a) sizeof argument expressions such as
`malloc(sizeof(MyType))`, and (b) casts such as `(MyType*)malloc(4096)`.

Note that non-standard allocation functions with these attributes are
not instrumented by default. Use `-fsanitize-alloc-token-extended` to
instrument them as well.

Link: 
https://discourse.llvm.org/t/rfc-a-framework-for-allocator-partitioning-hints/87434

---

This change is part of the following series:
  1. https://github.com/llvm/llvm-project/pull/160131
  2. https://github.com/llvm/llvm-project/pull/156838
  3. https://github.com/llvm/llvm-project/pull/162098
  4. https://github.com/llvm/llvm-project/pull/162099
  5. https://github.com/llvm/llvm-project/pull/156839
  6. https://github.com/llvm/llvm-project/pull/156840
  7. https://github.com/llvm/llvm-project/pull/156841
  8. https://github.com/llvm/llvm-project/pull/156842

Added: 
    clang/test/CodeGen/alloc-token-nonlibcalls.c

Modified: 
    clang/docs/AllocToken.rst
    clang/lib/CodeGen/CGExpr.cpp
    clang/lib/CodeGen/CGExprCXX.cpp
    clang/lib/CodeGen/CGExprScalar.cpp
    clang/lib/CodeGen/CodeGenFunction.h
    clang/test/CodeGen/alloc-token-lower.c
    clang/test/CodeGen/alloc-token.c
    clang/test/CodeGenCXX/alloc-token-pointer.cpp
    clang/test/CodeGenCXX/alloc-token.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/AllocToken.rst b/clang/docs/AllocToken.rst
index 7f3a128cd1557..bda84669456ce 100644
--- a/clang/docs/AllocToken.rst
+++ b/clang/docs/AllocToken.rst
@@ -122,6 +122,35 @@ which encodes the token ID hint in the allocation function 
name.
 This ABI provides a more efficient alternative where
 ``-falloc-token-max`` is small.
 
+Instrumenting Non-Standard Allocation Functions
+-----------------------------------------------
+
+By default, AllocToken only instruments standard library allocation functions.
+This simplifies adoption, as a compatible allocator only needs to provide
+token-enabled variants for a well-defined set of standard functions.
+
+To extend instrumentation to custom allocation functions, enable broader
+coverage with ``-fsanitize-alloc-token-extended``. Such functions require being
+marked with the `malloc
+<https://clang.llvm.org/docs/AttributeReference.html#malloc>`_ or `alloc_size
+<https://clang.llvm.org/docs/AttributeReference.html#alloc-size>`_ attributes
+(or a combination).
+
+For example:
+
+.. code-block:: c
+
+    void *custom_malloc(size_t size) __attribute__((malloc));
+    void *my_malloc(size_t size) __attribute__((alloc_size(1)));
+
+    // Original:
+    ptr1 = custom_malloc(size);
+    ptr2 = my_malloc(size);
+
+    // Instrumented:
+    ptr1 = __alloc_token_custom_malloc(size, token_id);
+    ptr2 = __alloc_token_my_malloc(size, token_id);
+
 Disabling Instrumentation
 -------------------------
 

diff  --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 7dd6a830502bd..e8255b0554da8 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -30,6 +30,7 @@
 #include "clang/AST/Attr.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/NSAPI.h"
+#include "clang/AST/ParentMapContext.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/CodeGenOptions.h"
@@ -1353,6 +1354,115 @@ void CodeGenFunction::EmitAllocToken(llvm::CallBase 
*CB, QualType AllocType) {
   CB->setMetadata(llvm::LLVMContext::MD_alloc_token, MDN);
 }
 
+namespace {
+/// Infer type from a simple sizeof expression.
+QualType inferTypeFromSizeofExpr(const Expr *E) {
+  const Expr *Arg = E->IgnoreParenImpCasts();
+  if (const auto *UET = dyn_cast<UnaryExprOrTypeTraitExpr>(Arg)) {
+    if (UET->getKind() == UETT_SizeOf) {
+      if (UET->isArgumentType())
+        return UET->getArgumentTypeInfo()->getType();
+      else
+        return UET->getArgumentExpr()->getType();
+    }
+  }
+  return QualType();
+}
+
+/// Infer type from an arithmetic expression involving a sizeof. For example:
+///
+///   malloc(sizeof(MyType) + padding);  // infers 'MyType'
+///   malloc(sizeof(MyType) * 32);       // infers 'MyType'
+///   malloc(32 * sizeof(MyType));       // infers 'MyType'
+///   malloc(sizeof(MyType) << 1);       // infers 'MyType'
+///   ...
+///
+/// More complex arithmetic expressions are supported, but are a heuristic, 
e.g.
+/// when considering allocations for structs with flexible array members:
+///
+///   malloc(sizeof(HasFlexArray) + sizeof(int) * 32);  // infers 
'HasFlexArray'
+///
+QualType inferPossibleTypeFromArithSizeofExpr(const Expr *E) {
+  const Expr *Arg = E->IgnoreParenImpCasts();
+  // The argument is a lone sizeof expression.
+  if (QualType T = inferTypeFromSizeofExpr(Arg); !T.isNull())
+    return T;
+  if (const auto *BO = dyn_cast<BinaryOperator>(Arg)) {
+    // Argument is an arithmetic expression. Cover common arithmetic patterns
+    // involving sizeof.
+    switch (BO->getOpcode()) {
+    case BO_Add:
+    case BO_Div:
+    case BO_Mul:
+    case BO_Shl:
+    case BO_Shr:
+    case BO_Sub:
+      if (QualType T = inferPossibleTypeFromArithSizeofExpr(BO->getLHS());
+          !T.isNull())
+        return T;
+      if (QualType T = inferPossibleTypeFromArithSizeofExpr(BO->getRHS());
+          !T.isNull())
+        return T;
+      break;
+    default:
+      break;
+    }
+  }
+  return QualType();
+}
+
+/// If the expression E is a reference to a variable, infer the type from a
+/// variable's initializer if it contains a sizeof. Beware, this is a heuristic
+/// and ignores if a variable is later reassigned. For example:
+///
+///   size_t my_size = sizeof(MyType);
+///   void *x = malloc(my_size);  // infers 'MyType'
+///
+QualType inferPossibleTypeFromVarInitSizeofExpr(const Expr *E) {
+  const Expr *Arg = E->IgnoreParenImpCasts();
+  if (const auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
+    if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+      if (const Expr *Init = VD->getInit())
+        return inferPossibleTypeFromArithSizeofExpr(Init);
+    }
+  }
+  return QualType();
+}
+
+/// Deduces the allocated type by checking if the allocation call's result
+/// is immediately used in a cast expression. For example:
+///
+///   MyType *x = (MyType *)malloc(4096);  // infers 'MyType'
+///
+QualType inferPossibleTypeFromCastExpr(const CallExpr *CallE,
+                                       const CastExpr *CastE) {
+  if (!CastE)
+    return QualType();
+  QualType PtrType = CastE->getType();
+  if (PtrType->isPointerType())
+    return PtrType->getPointeeType();
+  return QualType();
+}
+} // end anonymous namespace
+
+void CodeGenFunction::EmitAllocToken(llvm::CallBase *CB, const CallExpr *E) {
+  QualType AllocType;
+  // First check arguments.
+  for (const Expr *Arg : E->arguments()) {
+    AllocType = inferPossibleTypeFromArithSizeofExpr(Arg);
+    if (AllocType.isNull())
+      AllocType = inferPossibleTypeFromVarInitSizeofExpr(Arg);
+    if (!AllocType.isNull())
+      break;
+  }
+  // Then check later casts.
+  if (AllocType.isNull())
+    AllocType = inferPossibleTypeFromCastExpr(E, CurCast);
+  // Emit if we were able to infer the type.
+  if (!AllocType.isNull())
+    EmitAllocToken(CB, AllocType);
+}
+
 CodeGenFunction::ComplexPairTy CodeGenFunction::
 EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
                          bool isInc, bool isPre) {
@@ -5723,6 +5833,9 @@ LValue CodeGenFunction::EmitConditionalOperatorLValue(
 /// are permitted with aggregate result, including noop aggregate casts, and
 /// cast from scalar to union.
 LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
+  auto RestoreCurCast =
+      llvm::make_scope_exit([this, Prev = CurCast] { CurCast = Prev; });
+  CurCast = E;
   switch (E->getCastKind()) {
   case CK_ToVoid:
   case CK_BitCast:
@@ -6668,16 +6781,24 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
   RValue Call = EmitCall(FnInfo, Callee, ReturnValue, Args, &LocalCallOrInvoke,
                          E == MustTailCall, E->getExprLoc());
 
-  // Generate function declaration DISuprogram in order to be used
-  // in debug info about call sites.
-  if (CGDebugInfo *DI = getDebugInfo()) {
-    if (auto *CalleeDecl = dyn_cast_or_null<FunctionDecl>(TargetDecl)) {
+  if (auto *CalleeDecl = dyn_cast_or_null<FunctionDecl>(TargetDecl)) {
+    // Generate function declaration DISuprogram in order to be used
+    // in debug info about call sites.
+    if (CGDebugInfo *DI = getDebugInfo()) {
       FunctionArgList Args;
       QualType ResTy = BuildFunctionArgList(CalleeDecl, Args);
       DI->EmitFuncDeclForCallSite(LocalCallOrInvoke,
                                   DI->getFunctionType(CalleeDecl, ResTy, Args),
                                   CalleeDecl);
     }
+    if (CalleeDecl->hasAttr<RestrictAttr>() ||
+        CalleeDecl->hasAttr<AllocSizeAttr>()) {
+      // Function has 'malloc' (aka. 'restrict') or 'alloc_size' attribute.
+      if (SanOpts.has(SanitizerKind::AllocToken)) {
+        // Set !alloc_token metadata.
+        EmitAllocToken(LocalCallOrInvoke, E);
+      }
+    }
   }
   if (CallOrInvoke)
     *CallOrInvoke = LocalCallOrInvoke;

diff  --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 290c2e0f1039c..31ac26662b4c8 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -1371,8 +1371,16 @@ RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const 
FunctionProtoType *Type,
 
   for (auto *Decl : Ctx.getTranslationUnitDecl()->lookup(Name))
     if (auto *FD = dyn_cast<FunctionDecl>(Decl))
-      if (Ctx.hasSameType(FD->getType(), QualType(Type, 0)))
-        return EmitNewDeleteCall(*this, FD, Type, Args);
+      if (Ctx.hasSameType(FD->getType(), QualType(Type, 0))) {
+        RValue RV = EmitNewDeleteCall(*this, FD, Type, Args);
+        if (auto *CB = dyn_cast_if_present<llvm::CallBase>(RV.getScalarVal())) 
{
+          if (SanOpts.has(SanitizerKind::AllocToken)) {
+            // Set !alloc_token metadata.
+            EmitAllocToken(CB, TheCall);
+          }
+        }
+        return RV;
+      }
   llvm_unreachable("predeclared global operator new/delete is missing");
 }
 

diff  --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index 06d9d812bc60b..715160d067817 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -33,6 +33,7 @@
 #include "clang/Basic/DiagnosticTrap.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/APFixedPoint.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/IR/Argument.h"
 #include "llvm/IR/CFG.h"
 #include "llvm/IR/Constants.h"
@@ -2434,6 +2435,10 @@ static Value *EmitHLSLElementwiseCast(CodeGenFunction 
&CGF, LValue SrcVal,
 // have to handle a more broad range of conversions than explicit casts, as 
they
 // handle things like function to ptr-to-function decay etc.
 Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
+  auto RestoreCurCast =
+      llvm::make_scope_exit([this, Prev = CGF.CurCast] { CGF.CurCast = Prev; 
});
+  CGF.CurCast = CE;
+
   Expr *E = CE->getSubExpr();
   QualType DestTy = CE->getType();
   CastKind Kind = CE->getCastKind();

diff  --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index e14e60c9bdc43..1f0be2d8756de 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -346,6 +346,10 @@ class CodeGenFunction : public CodeGenTypeCache {
   QualType FnRetTy;
   llvm::Function *CurFn = nullptr;
 
+  /// If a cast expression is being visited, this holds the current cast's
+  /// expression.
+  const CastExpr *CurCast = nullptr;
+
   /// Save Parameter Decl for coroutine.
   llvm::SmallVector<const ParmVarDecl *, 4> FnArgs;
 
@@ -3350,6 +3354,9 @@ class CodeGenFunction : public CodeGenTypeCache {
 
   /// Emit additional metadata used by the AllocToken instrumentation.
   void EmitAllocToken(llvm::CallBase *CB, QualType AllocType);
+  /// Emit additional metadata used by the AllocToken instrumentation,
+  /// inferring the type from an allocation call expression.
+  void EmitAllocToken(llvm::CallBase *CB, const CallExpr *E);
 
   llvm::Value *GetCountedByFieldExprGEP(const Expr *Base, const FieldDecl *FD,
                                         const FieldDecl *CountDecl);

diff  --git a/clang/test/CodeGen/alloc-token-lower.c 
b/clang/test/CodeGen/alloc-token-lower.c
index 75197bb3dbd44..43d9a6337b7db 100644
--- a/clang/test/CodeGen/alloc-token-lower.c
+++ b/clang/test/CodeGen/alloc-token-lower.c
@@ -10,7 +10,7 @@ typedef __typeof(sizeof(int)) size_t;
 void *malloc(size_t size);
 
 // CHECK-LABEL: @test_malloc(
-// CHECK: call{{.*}} ptr @__alloc_token_malloc(i64 noundef 4, i64 0)
+// CHECK: call{{.*}} ptr @__alloc_token_malloc(i64 noundef 4, i64 
2689373973731826898){{.*}} !alloc_token [[META_INT:![0-9]+]]
 void *test_malloc() {
   return malloc(sizeof(int));
 }
@@ -20,3 +20,15 @@ void *test_malloc() {
 void *no_sanitize_malloc(size_t size) 
__attribute__((no_sanitize("alloc-token"))) {
   return malloc(sizeof(int));
 }
+
+// By default, we should not be touching malloc-attributed non-libcall
+// functions: there might be an arbitrary number of these, and a compatible
+// allocator will only implement standard allocation functions.
+void *nonstandard_malloc(size_t size) __attribute__((malloc));
+// CHECK-LABEL: @test_nonlibcall_malloc(
+// CHECK: call{{.*}} ptr @nonstandard_malloc(i64 noundef 4){{.*}} !alloc_token 
[[META_INT]]
+void *test_nonlibcall_malloc() {
+  return nonstandard_malloc(sizeof(int));
+}
+
+// CHECK: [[META_INT]] = !{!"int", i1 false}

diff  --git a/clang/test/CodeGen/alloc-token-nonlibcalls.c 
b/clang/test/CodeGen/alloc-token-nonlibcalls.c
new file mode 100644
index 0000000000000..da81becf4b352
--- /dev/null
+++ b/clang/test/CodeGen/alloc-token-nonlibcalls.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1    -fsanitize=alloc-token -fsanitize-alloc-token-extended 
-triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes %s -o - | FileCheck 
--check-prefixes=CHECK,CHECK-CODEGEN %s
+// RUN: %clang_cc1    -fsanitize=alloc-token -fsanitize-alloc-token-extended 
-triple x86_64-linux-gnu -emit-llvm                      %s -o - | FileCheck 
--check-prefixes=CHECK,CHECK-LOWER %s
+// RUN: %clang_cc1 -O -fsanitize=alloc-token -fsanitize-alloc-token-extended 
-triple x86_64-linux-gnu -emit-llvm                      %s -o - | FileCheck 
--check-prefixes=CHECK,CHECK-LOWER %s
+
+typedef __typeof(sizeof(int)) size_t;
+typedef size_t gfp_t;
+
+void *custom_malloc(size_t size) __attribute__((malloc));
+void *__kmalloc(size_t size, gfp_t flags) __attribute__((alloc_size(1)));
+
+void *sink;
+
+// CHECK-LABEL: @test_nonlibcall_alloc(
+// CHECK-CODEGEN: call noalias ptr @custom_malloc(i64 noundef 4){{.*}} 
!alloc_token [[META_INT:![0-9]+]]
+// CHECK-CODEGEN: call ptr @__kmalloc(i64 noundef 4, i64 noundef 0){{.*}} 
!alloc_token [[META_INT]]
+// CHECK-LOWER: call{{.*}} noalias ptr @__alloc_token_custom_malloc(i64 
noundef 4, i64 2689373973731826898){{.*}} !alloc_token [[META_INT:![0-9]+]]
+// CHECK-LOWER: call{{.*}} ptr @__alloc_token___kmalloc(i64 noundef 4, i64 
noundef 0, i64 2689373973731826898){{.*}} !alloc_token [[META_INT]]
+void test_nonlibcall_alloc() {
+  sink = custom_malloc(sizeof(int));
+  sink = __kmalloc(sizeof(int), 0);
+}
+
+// CHECK: [[META_INT]] = !{!"int", i1 false}

diff  --git a/clang/test/CodeGen/alloc-token.c 
b/clang/test/CodeGen/alloc-token.c
index d1160adc060ba..3c9b4d8f0e910 100644
--- a/clang/test/CodeGen/alloc-token.c
+++ b/clang/test/CodeGen/alloc-token.c
@@ -2,36 +2,39 @@
 
 typedef __typeof(sizeof(int)) size_t;
 
-void *aligned_alloc(size_t alignment, size_t size);
-void *malloc(size_t size);
-void *calloc(size_t num, size_t size);
-void *realloc(void *ptr, size_t size);
-void *reallocarray(void *ptr, size_t nmemb, size_t size);
-void *memalign(size_t alignment, size_t size);
-void *valloc(size_t size);
-void *pvalloc(size_t size);
+void *aligned_alloc(size_t alignment, size_t size) __attribute__((malloc));
+void *malloc(size_t size) __attribute__((malloc));
+void *calloc(size_t num, size_t size) __attribute__((malloc));
+void *realloc(void *ptr, size_t size) __attribute__((malloc));
+void *reallocarray(void *ptr, size_t nmemb, size_t size) 
__attribute__((malloc));
+void *memalign(size_t alignment, size_t size) __attribute__((malloc));
+void *valloc(size_t size) __attribute__((malloc));
+void *pvalloc(size_t size) __attribute__((malloc));
 int posix_memalign(void **memptr, size_t alignment, size_t size);
 
 void *sink;
 
 // CHECK-LABEL: define dso_local void @test_malloc_like(
-// CHECK: call ptr @malloc(i64 noundef 4)
-// CHECK: call ptr @calloc(i64 noundef 3, i64 noundef 4)
-// CHECK: call ptr @realloc(ptr noundef {{.*}}, i64 noundef 8)
-// CHECK: call ptr @reallocarray(ptr noundef {{.*}}, i64 noundef 5, i64 
noundef 8)
-// CHECK: call align 128 ptr @aligned_alloc(i64 noundef 128, i64 noundef 1024)
-// CHECK: call align 16 ptr @memalign(i64 noundef 16, i64 noundef 256)
-// CHECK: call ptr @valloc(i64 noundef 4096)
-// CHECK: call ptr @pvalloc(i64 noundef 8192)
+// CHECK: call noalias ptr @malloc(i64 noundef 4){{.*}} !alloc_token 
[[META_INT:![0-9]+]]
+// CHECK: call noalias ptr @calloc(i64 noundef 3, i64 noundef 4){{.*}} 
!alloc_token [[META_INT]]
+// CHECK: call noalias ptr @realloc(ptr noundef {{.*}}, i64 noundef 8){{.*}} 
!alloc_token [[META_LONG:![0-9]+]]
+// CHECK: call noalias ptr @reallocarray(ptr noundef {{.*}}, i64 noundef 5, 
i64 noundef 8), !alloc_token [[META_LONG]]
+// CHECK: call noalias align 128 ptr @aligned_alloc(i64 noundef 128, i64 
noundef 4){{.*}} !alloc_token [[META_INT]]
+// CHECK: call noalias align 16 ptr @memalign(i64 noundef 16, i64 noundef 
4){{.*}} !alloc_token [[META_INT]]
+// CHECK: call noalias ptr @valloc(i64 noundef 4), !alloc_token [[META_INT]]
+// CHECK: call noalias ptr @pvalloc(i64 noundef 4), !alloc_token [[META_INT]]
 // CHECK: call i32 @posix_memalign(ptr noundef @sink, i64 noundef 64, i64 
noundef 4)
 void test_malloc_like() {
   sink = malloc(sizeof(int));
   sink = calloc(3, sizeof(int));
   sink = realloc(sink, sizeof(long));
   sink = reallocarray(sink, 5, sizeof(long));
-  sink = aligned_alloc(128, 1024);
-  sink = memalign(16, 256);
-  sink = valloc(4096);
-  sink = pvalloc(8192);
-  posix_memalign(&sink, 64, sizeof(int));
+  sink = aligned_alloc(128, sizeof(int));
+  sink = memalign(16, sizeof(int));
+  sink = valloc(sizeof(int));
+  sink = pvalloc(sizeof(int));
+  posix_memalign(&sink, 64, sizeof(int)); // FIXME: support posix_memalign
 }
+
+// CHECK: [[META_INT]] = !{!"int", i1 false}
+// CHECK: [[META_LONG]] = !{!"long", i1 false}

diff  --git a/clang/test/CodeGenCXX/alloc-token-pointer.cpp 
b/clang/test/CodeGenCXX/alloc-token-pointer.cpp
index 4781d1b4c13f0..f12ee7a40a6b8 100644
--- a/clang/test/CodeGenCXX/alloc-token-pointer.cpp
+++ b/clang/test/CodeGenCXX/alloc-token-pointer.cpp
@@ -5,11 +5,13 @@
 typedef __UINTPTR_TYPE__ uintptr_t;
 
 extern "C" {
-void *malloc(size_t size);
+void *malloc(size_t size) __attribute__((malloc));
 }
 
+void *sink; // prevent optimizations from removing the calls
+
 // CHECK-LABEL: define dso_local noundef ptr @_Z15test_malloc_intv(
-// CHECK: call ptr @malloc(i64 noundef 4)
+// CHECK: call noalias ptr @malloc(i64 noundef 4){{.*}} !alloc_token 
[[META_INT:![0-9]+]]
 void *test_malloc_int() {
   int *a = (int *)malloc(sizeof(int));
   *a = 42;
@@ -17,7 +19,7 @@ void *test_malloc_int() {
 }
 
 // CHECK-LABEL: define dso_local noundef ptr @_Z15test_malloc_ptrv(
-// CHECK: call ptr @malloc(i64 noundef 8)
+// CHECK: call noalias ptr @malloc(i64 noundef 8){{.*}} !alloc_token 
[[META_INTPTR:![0-9]+]]
 int **test_malloc_ptr() {
   int **a = (int **)malloc(sizeof(int*));
   *a = nullptr;
@@ -25,7 +27,7 @@ int **test_malloc_ptr() {
 }
 
 // CHECK-LABEL: define dso_local noundef ptr @_Z12test_new_intv(
-// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 4){{.*}} 
!alloc_token [[META_INT:![0-9]+]]
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 4){{.*}} 
!alloc_token [[META_INT]]
 int *test_new_int() {
   return new int;
 }
@@ -37,7 +39,7 @@ unsigned long *test_new_ulong_array() {
 }
 
 // CHECK-LABEL: define dso_local noundef ptr @_Z12test_new_ptrv(
-// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 8){{.*}} 
!alloc_token [[META_INTPTR:![0-9]+]]
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 8){{.*}} 
!alloc_token [[META_INTPTR]]
 int **test_new_ptr() {
   return new int*;
 }
@@ -54,49 +56,69 @@ struct ContainsPtr {
 };
 
 // CHECK-LABEL: define dso_local noundef ptr @_Z27test_malloc_struct_with_ptrv(
-// CHECK: call ptr @malloc(i64 noundef 16)
-ContainsPtr *test_malloc_struct_with_ptr() {
-  ContainsPtr *c = (ContainsPtr *)malloc(sizeof(ContainsPtr));
-  return c;
+// CHECK: call noalias ptr @malloc(i64 noundef 16){{.*}} !alloc_token 
[[META_CONTAINSPTR:![0-9]+]]
+void *test_malloc_struct_with_ptr() {
+  return malloc(sizeof(ContainsPtr));
 }
 
 // CHECK-LABEL: define dso_local noundef ptr 
@_Z33test_malloc_struct_array_with_ptrv(
-// CHECK: call ptr @malloc(i64 noundef 160)
-ContainsPtr *test_malloc_struct_array_with_ptr() {
-  ContainsPtr *c = (ContainsPtr *)malloc(10 * sizeof(ContainsPtr));
-  return c;
+// CHECK: call noalias ptr @malloc(i64 noundef 160){{.*}} !alloc_token 
[[META_CONTAINSPTR]]
+void *test_malloc_struct_array_with_ptr() {
+  return malloc(10 * sizeof(ContainsPtr));
+}
+
+// CHECK-LABEL: define dso_local noundef ptr 
@_Z31test_malloc_with_ptr_sizeof_vari(
+// CHECK: call noalias ptr @malloc(i64 noundef {{.*}}){{.*}} !alloc_token 
[[META_CONTAINSPTR]]
+void *test_malloc_with_ptr_sizeof_var(int x) {
+  unsigned long size = sizeof(ContainsPtr);
+  size *= x;
+  return malloc(size);
+}
+
+// CHECK-LABEL: define dso_local noundef ptr 
@_Z29test_malloc_with_ptr_castonlyv(
+// CHECK: call noalias ptr @malloc(i64 noundef 4096){{.*}} !alloc_token 
[[META_CONTAINSPTR]]
+ContainsPtr *test_malloc_with_ptr_castonly() {
+  return (ContainsPtr *)malloc(4096);
 }
 
 // CHECK-LABEL: define dso_local noundef ptr 
@_Z32test_operatornew_struct_with_ptrv(
-// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 16)
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 16){{.*}} 
!alloc_token [[META_CONTAINSPTR]]
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 16){{.*}} 
!alloc_token [[META_CONTAINSPTR]]
 ContainsPtr *test_operatornew_struct_with_ptr() {
   ContainsPtr *c = (ContainsPtr *)__builtin_operator_new(sizeof(ContainsPtr));
+  sink = ::operator new(sizeof(ContainsPtr));
   return c;
 }
 
 // CHECK-LABEL: define dso_local noundef ptr 
@_Z38test_operatornew_struct_array_with_ptrv(
-// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 160)
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 160){{.*}} 
!alloc_token [[META_CONTAINSPTR]]
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 160){{.*}} 
!alloc_token [[META_CONTAINSPTR]]
 ContainsPtr *test_operatornew_struct_array_with_ptr() {
   ContainsPtr *c = (ContainsPtr *)__builtin_operator_new(10 * 
sizeof(ContainsPtr));
+  sink = ::operator new(10 * sizeof(ContainsPtr));
   return c;
 }
 
 // CHECK-LABEL: define dso_local noundef ptr 
@_Z33test_operatornew_struct_with_ptr2v(
-// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 16)
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 16){{.*}} 
!alloc_token [[META_CONTAINSPTR]]
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 16){{.*}} 
!alloc_token [[META_CONTAINSPTR]]
 ContainsPtr *test_operatornew_struct_with_ptr2() {
   ContainsPtr *c = (ContainsPtr *)__builtin_operator_new(sizeof(*c));
+  sink = ::operator new(sizeof(*c));
   return c;
 }
 
 // CHECK-LABEL: define dso_local noundef ptr 
@_Z39test_operatornew_struct_array_with_ptr2v(
-// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 160)
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 160){{.*}} 
!alloc_token [[META_CONTAINSPTR]]
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 160){{.*}} 
!alloc_token [[META_CONTAINSPTR]]
 ContainsPtr *test_operatornew_struct_array_with_ptr2() {
   ContainsPtr *c = (ContainsPtr *)__builtin_operator_new(10 * sizeof(*c));
+  sink = ::operator new(10 * sizeof(*c));
   return c;
 }
 
 // CHECK-LABEL: define dso_local noundef ptr @_Z24test_new_struct_with_ptrv(
-// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 16){{.*}} 
!alloc_token [[META_CONTAINSPTR:![0-9]+]]
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 16){{.*}} 
!alloc_token [[META_CONTAINSPTR]]
 ContainsPtr *test_new_struct_with_ptr() {
   return new ContainsPtr;
 }
@@ -166,8 +188,8 @@ uptr *test_uintptr_isptr2() {
 }
 
 // CHECK: [[META_INT]] = !{!"int", i1 false}
-// CHECK: [[META_ULONG]] = !{!"unsigned long", i1 false}
 // CHECK: [[META_INTPTR]] = !{!"int *", i1 true}
+// CHECK: [[META_ULONG]] = !{!"unsigned long", i1 false}
 // CHECK: [[META_CONTAINSPTR]] = !{!"ContainsPtr", i1 true}
 // CHECK: [[META_TESTCLASS]] = !{!"TestClass", i1 false}
 // CHECK: [[META_VIRTUALTESTCLASS]] = !{!"VirtualTestClass", i1 true}

diff  --git a/clang/test/CodeGenCXX/alloc-token.cpp 
b/clang/test/CodeGenCXX/alloc-token.cpp
index 5914b4ca5ef23..feed808a3b89b 100644
--- a/clang/test/CodeGenCXX/alloc-token.cpp
+++ b/clang/test/CodeGenCXX/alloc-token.cpp
@@ -2,14 +2,14 @@
 
 #include "../Analysis/Inputs/system-header-simulator-cxx.h"
 extern "C" {
-void *aligned_alloc(size_t alignment, size_t size);
-void *malloc(size_t size);
-void *calloc(size_t num, size_t size);
-void *realloc(void *ptr, size_t size);
-void *reallocarray(void *ptr, size_t nmemb, size_t size);
-void *memalign(size_t alignment, size_t size);
-void *valloc(size_t size);
-void *pvalloc(size_t size);
+void *aligned_alloc(size_t alignment, size_t size) __attribute__((malloc));
+void *malloc(size_t size) __attribute__((malloc));
+void *calloc(size_t num, size_t size) __attribute__((malloc));
+void *realloc(void *ptr, size_t size) __attribute__((malloc));
+void *reallocarray(void *ptr, size_t nmemb, size_t size) 
__attribute__((malloc));
+void *memalign(size_t alignment, size_t size) __attribute__((malloc));
+void *valloc(size_t size) __attribute__((malloc));
+void *pvalloc(size_t size) __attribute__((malloc));
 int posix_memalign(void **memptr, size_t alignment, size_t size);
 
 struct __sized_ptr_t {
@@ -26,45 +26,58 @@ __sized_ptr_t __size_returning_new_aligned_hot_cold(size_t, 
std::align_val_t,  _
 void *sink; // prevent optimizations from removing the calls
 
 // CHECK-LABEL: define dso_local void @_Z16test_malloc_likev(
-// CHECK: call ptr @malloc(i64 noundef 4)
-// CHECK: call ptr @calloc(i64 noundef 3, i64 noundef 4)
-// CHECK: call ptr @realloc(ptr noundef {{.*}}, i64 noundef 8)
-// CHECK: call ptr @reallocarray(ptr noundef {{.*}}, i64 noundef 5, i64 
noundef 8)
-// CHECK: call align 128 ptr @aligned_alloc(i64 noundef 128, i64 noundef 1024)
-// CHECK: call ptr @memalign(i64 noundef 16, i64 noundef 256)
-// CHECK: call ptr @valloc(i64 noundef 4096)
-// CHECK: call ptr @pvalloc(i64 noundef 8192)
+// CHECK: call noalias ptr @malloc(i64 noundef 4){{.*}} !alloc_token 
[[META_INT:![0-9]+]]
+// CHECK: call noalias ptr @calloc(i64 noundef 3, i64 noundef 4){{.*}} 
!alloc_token [[META_INT]]
+// CHECK: call noalias ptr @realloc(ptr noundef {{.*}}, i64 noundef 8){{.*}} 
!alloc_token [[META_LONG:![0-9]+]]
+// CHECK: call noalias ptr @reallocarray(ptr noundef {{.*}}, i64 noundef 5, 
i64 noundef 8), !alloc_token [[META_LONG]]
+// CHECK: call noalias align 128 ptr @aligned_alloc(i64 noundef 128, i64 
noundef 4){{.*}} !alloc_token [[META_INT]]
+// CHECK: call noalias ptr @memalign(i64 noundef 16, i64 noundef 4), 
!alloc_token [[META_INT]]
+// CHECK: call noalias ptr @valloc(i64 noundef 4), !alloc_token [[META_INT]]
+// CHECK: call noalias ptr @pvalloc(i64 noundef 4), !alloc_token [[META_INT]]
 // CHECK: call i32 @posix_memalign(ptr noundef @sink, i64 noundef 64, i64 
noundef 4)
 void test_malloc_like() {
   sink = malloc(sizeof(int));
   sink = calloc(3, sizeof(int));
   sink = realloc(sink, sizeof(long));
   sink = reallocarray(sink, 5, sizeof(long));
-  sink = aligned_alloc(128, 1024);
-  sink = memalign(16, 256);
-  sink = valloc(4096);
-  sink = pvalloc(8192);
-  posix_memalign(&sink, 64, sizeof(int));
+  sink = aligned_alloc(128, sizeof(int));
+  sink = memalign(16, sizeof(int));
+  sink = valloc(sizeof(int));
+  sink = pvalloc(sizeof(int));
+  posix_memalign(&sink, 64, sizeof(int)); // FIXME: support posix_memalign
+}
+
+class ForwardDecl;
+
+// CHECK-LABEL: define dso_local void @_Z21test_malloc_like_castv(
+// CHECK: call noalias ptr @malloc(i64 noundef 64){{.*}} !alloc_token 
[[META_INT]]
+// CHECK: call noalias ptr @malloc(i64 noundef 64){{.*}} !alloc_token 
[[META_INT]]
+// CHECK-NOT: call noalias ptr @malloc(i64 noundef 64){{.*}} !alloc_token 
[[META_INT]]
+void test_malloc_like_cast() {
+  sink = (int *)malloc(64);
+  sink = reinterpret_cast<int *>(malloc(64));
+  // Always fails to assign token ID for incomplete types.
+  sink = reinterpret_cast<ForwardDecl *>(malloc(64));
 }
 
 // CHECK-LABEL: define dso_local void @_Z17test_operator_newv(
-// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 4)
-// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 4)
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 4){{.*}} 
!alloc_token [[META_INT]]
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 4){{.*}} 
!alloc_token [[META_INT]]
 void test_operator_new() {
   sink = __builtin_operator_new(sizeof(int));
   sink = ::operator new(sizeof(int));
 }
 
 // CHECK-LABEL: define dso_local void @_Z25test_operator_new_nothrowv(
-// CHECK: call noalias noundef ptr @_ZnwmRKSt9nothrow_t(i64 noundef 4, ptr 
noundef nonnull align 1 dereferenceable(1) @_ZSt7nothrow)
-// CHECK: call noalias noundef ptr @_ZnwmRKSt9nothrow_t(i64 noundef 4, ptr 
noundef nonnull align 1 dereferenceable(1) @_ZSt7nothrow)
+// CHECK: call noalias noundef ptr @_ZnwmRKSt9nothrow_t(i64 noundef 4, ptr 
noundef nonnull align 1 dereferenceable(1) @_ZSt7nothrow){{.*}} !alloc_token 
[[META_INT]]
+// CHECK: call noalias noundef ptr @_ZnwmRKSt9nothrow_t(i64 noundef 4, ptr 
noundef nonnull align 1 dereferenceable(1) @_ZSt7nothrow){{.*}} !alloc_token 
[[META_INT]]
 void test_operator_new_nothrow() {
   sink = __builtin_operator_new(sizeof(int), std::nothrow);
   sink = ::operator new(sizeof(int), std::nothrow);
 }
 
 // CHECK-LABEL: define dso_local noundef ptr @_Z8test_newv(
-// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 4){{.*}} 
!alloc_token [[META_INT:![0-9]+]]
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 4){{.*}} 
!alloc_token [[META_INT]]
 int *test_new() {
   return new int;
 }
@@ -93,6 +106,7 @@ int *test_new_array_nothrow() {
 // CHECK: call { ptr, i64 } @__size_returning_new_aligned(i64 noundef 8, i64 
noundef 32)
 // CHECK: call { ptr, i64 } @__size_returning_new_aligned_hot_cold(i64 noundef 
8, i64 noundef 32, i8 noundef zeroext 1)
 void test_size_returning_new() {
+  // FIXME: Support __size_returning_new variants.
   sink = __size_returning_new(sizeof(long)).p;
   sink = __size_returning_new_hot_cold(sizeof(long), __hot_cold_t{1}).p;
   sink = __size_returning_new_aligned(sizeof(long), std::align_val_t{32}).p;
@@ -138,4 +152,5 @@ TestClass *test_new_class_array() {
 }
 
 // CHECK: [[META_INT]] = !{!"int", i1 false}
+// CHECK: [[META_LONG]] = !{!"long", i1 false}
 // CHECK: [[META_TESTCLASS]] = !{!"TestClass", i1 true}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to