[llvm] 6359980 - [AllocToken, Clang] Implement TypeHashPointerSplit mode (#156840)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 8 12:58:42 PDT 2025
Author: Marco Elver
Date: 2025-10-08T21:58:37+02:00
New Revision: 6359980f5b555f95429139c2e2e9530d75d4e78f
URL: https://github.com/llvm/llvm-project/commit/6359980f5b555f95429139c2e2e9530d75d4e78f
DIFF: https://github.com/llvm/llvm-project/commit/6359980f5b555f95429139c2e2e9530d75d4e78f.diff
LOG: [AllocToken, Clang] Implement TypeHashPointerSplit mode (#156840)
Implement the TypeHashPointerSplit mode: This mode assigns a token ID
based on the hash of the allocated type's name, where the top half
ID-space is reserved for types that contain pointers and the bottom half
for types that do not contain pointers.
This mode with max tokens of 2 (`-falloc-token-max=2`) may also
be valuable for heap hardening strategies that simply separate pointer
types from non-pointer types.
Make it the new default mode.
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/CodeGenCXX/alloc-token-pointer.cpp
llvm/test/Instrumentation/AllocToken/typehashpointersplit.ll
Modified:
clang/docs/AllocToken.rst
clang/lib/CodeGen/CGExpr.cpp
clang/test/CodeGenCXX/alloc-token.cpp
llvm/docs/LangRef.rst
llvm/lib/IR/Verifier.cpp
llvm/lib/Transforms/Instrumentation/AllocToken.cpp
llvm/test/Instrumentation/AllocToken/extralibfuncs.ll
llvm/test/Instrumentation/AllocToken/nonlibcalls.ll
llvm/test/Instrumentation/AllocToken/remark.ll
llvm/test/Transforms/SimplifyCFG/merge-calls-alloc-token.ll
Removed:
################################################################################
diff --git a/clang/docs/AllocToken.rst b/clang/docs/AllocToken.rst
index fb5c060bed939..7f3a128cd1557 100644
--- a/clang/docs/AllocToken.rst
+++ b/clang/docs/AllocToken.rst
@@ -31,13 +31,18 @@ Token Assignment Mode
The default mode to calculate tokens is:
-* ``typehash``: This mode assigns a token ID based on the hash of the allocated
- type's name.
+* ``typehashpointersplit``: This mode assigns a token ID based on the hash of
+ the allocated type's name, where the top half ID-space is reserved for types
+ that contain pointers and the bottom half for types that do not contain
+ pointers.
Other token ID assignment modes are supported, but they may be subject to
change or removal. These may (experimentally) be selected with ``-mllvm
-alloc-token-mode=<mode>``:
+* ``typehash``: This mode assigns a token ID based on the hash of the allocated
+ type's name.
+
* ``random``: This mode assigns a statically-determined random token ID to each
allocation site.
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index a071e801b91ec..7dd6a830502bd 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1272,20 +1272,84 @@ void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
EmitCheck(std::make_pair(Check, CheckKind), CheckHandler, StaticData, Index);
}
+static bool
+typeContainsPointer(QualType T,
+ llvm::SmallPtrSet<const RecordDecl *, 4> &VisitedRD,
+ bool &IncompleteType) {
+ QualType CanonicalType = T.getCanonicalType();
+ if (CanonicalType->isPointerType())
+ return true; // base case
+
+ // Look through typedef chain to check for special types.
+ for (QualType CurrentT = T; const auto *TT = CurrentT->getAs<TypedefType>();
+ CurrentT = TT->getDecl()->getUnderlyingType()) {
+ const IdentifierInfo *II = TT->getDecl()->getIdentifier();
+ // Special Case: Syntactically uintptr_t is not a pointer; semantically,
+ // however, very likely used as such. Therefore, classify uintptr_t as a
+ // pointer, too.
+ if (II && II->isStr("uintptr_t"))
+ return true;
+ }
+
+ // The type is an array; check the element type.
+ if (const ArrayType *AT = dyn_cast<ArrayType>(CanonicalType))
+ return typeContainsPointer(AT->getElementType(), VisitedRD, IncompleteType);
+ // The type is a struct, class, or union.
+ if (const RecordDecl *RD = CanonicalType->getAsRecordDecl()) {
+ if (!RD->isCompleteDefinition()) {
+ IncompleteType = true;
+ return false;
+ }
+ if (!VisitedRD.insert(RD).second)
+ return false; // already visited
+ // Check all fields.
+ for (const FieldDecl *Field : RD->fields()) {
+ if (typeContainsPointer(Field->getType(), VisitedRD, IncompleteType))
+ return true;
+ }
+ // For C++ classes, also check base classes.
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ // Polymorphic types require a vptr.
+ if (CXXRD->isDynamicClass())
+ return true;
+ for (const CXXBaseSpecifier &Base : CXXRD->bases()) {
+ if (typeContainsPointer(Base.getType(), VisitedRD, IncompleteType))
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void CodeGenFunction::EmitAllocToken(llvm::CallBase *CB, QualType AllocType) {
assert(SanOpts.has(SanitizerKind::AllocToken) &&
"Only needed with -fsanitize=alloc-token");
+ llvm::MDBuilder MDB(getLLVMContext());
+
+ // Get unique type name.
PrintingPolicy Policy(CGM.getContext().getLangOpts());
Policy.SuppressTagKeyword = true;
Policy.FullyQualifiedName = true;
SmallString<64> TypeName;
llvm::raw_svector_ostream TypeNameOS(TypeName);
AllocType.getCanonicalType().print(TypeNameOS, Policy);
- auto *TypeMDS = llvm::MDString::get(CGM.getLLVMContext(), TypeNameOS.str());
+ auto *TypeNameMD = MDB.createString(TypeNameOS.str());
+
+ // Check if QualType contains a pointer. Implements a simple DFS to
+ // recursively check if a type contains a pointer type.
+ llvm::SmallPtrSet<const RecordDecl *, 4> VisitedRD;
+ bool IncompleteType = false;
+ const bool ContainsPtr =
+ typeContainsPointer(AllocType, VisitedRD, IncompleteType);
+ if (!ContainsPtr && IncompleteType)
+ return;
+ auto *ContainsPtrC = Builder.getInt1(ContainsPtr);
+ auto *ContainsPtrMD = MDB.createConstant(ContainsPtrC);
- // Format: !{<type-name>}
- auto *MDN = llvm::MDNode::get(CGM.getLLVMContext(), {TypeMDS});
+ // Format: !{<type-name>, <contains-pointer>}
+ auto *MDN =
+ llvm::MDNode::get(CGM.getLLVMContext(), {TypeNameMD, ContainsPtrMD});
CB->setMetadata(llvm::LLVMContext::MD_alloc_token, MDN);
}
diff --git a/clang/test/CodeGenCXX/alloc-token-pointer.cpp b/clang/test/CodeGenCXX/alloc-token-pointer.cpp
new file mode 100644
index 0000000000000..4781d1b4c13f0
--- /dev/null
+++ b/clang/test/CodeGenCXX/alloc-token-pointer.cpp
@@ -0,0 +1,175 @@
+// RUN: %clang_cc1 -fsanitize=alloc-token -triple x86_64-linux-gnu -std=c++20 -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s
+
+#include "../Analysis/Inputs/system-header-simulator-cxx.h"
+
+typedef __UINTPTR_TYPE__ uintptr_t;
+
+extern "C" {
+void *malloc(size_t size);
+}
+
+// CHECK-LABEL: define dso_local noundef ptr @_Z15test_malloc_intv(
+// CHECK: call ptr @malloc(i64 noundef 4)
+void *test_malloc_int() {
+ int *a = (int *)malloc(sizeof(int));
+ *a = 42;
+ return a;
+}
+
+// CHECK-LABEL: define dso_local noundef ptr @_Z15test_malloc_ptrv(
+// CHECK: call ptr @malloc(i64 noundef 8)
+int **test_malloc_ptr() {
+ int **a = (int **)malloc(sizeof(int*));
+ *a = nullptr;
+ return a;
+}
+
+// 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]+]]
+int *test_new_int() {
+ return new int;
+}
+
+// CHECK-LABEL: define dso_local noundef ptr @_Z20test_new_ulong_arrayv(
+// CHECK: call noalias noundef nonnull ptr @_Znam(i64 noundef 80){{.*}} !alloc_token [[META_ULONG:![0-9]+]]
+unsigned long *test_new_ulong_array() {
+ return new unsigned long[10];
+}
+
+// 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]+]]
+int **test_new_ptr() {
+ return new int*;
+}
+
+// CHECK-LABEL: define dso_local noundef ptr @_Z18test_new_ptr_arrayv(
+// CHECK: call noalias noundef nonnull ptr @_Znam(i64 noundef 80){{.*}} !alloc_token [[META_INTPTR]]
+int **test_new_ptr_array() {
+ return new int*[10];
+}
+
+struct ContainsPtr {
+ int a;
+ char *buf;
+};
+
+// 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-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-LABEL: define dso_local noundef ptr @_Z32test_operatornew_struct_with_ptrv(
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 16)
+ContainsPtr *test_operatornew_struct_with_ptr() {
+ ContainsPtr *c = (ContainsPtr *)__builtin_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)
+ContainsPtr *test_operatornew_struct_array_with_ptr() {
+ ContainsPtr *c = (ContainsPtr *)__builtin_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)
+ContainsPtr *test_operatornew_struct_with_ptr2() {
+ ContainsPtr *c = (ContainsPtr *)__builtin_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)
+ContainsPtr *test_operatornew_struct_array_with_ptr2() {
+ ContainsPtr *c = (ContainsPtr *)__builtin_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]+]]
+ContainsPtr *test_new_struct_with_ptr() {
+ return new ContainsPtr;
+}
+
+// CHECK-LABEL: define dso_local noundef ptr @_Z30test_new_struct_array_with_ptrv(
+// CHECK: call noalias noundef nonnull ptr @_Znam(i64 noundef 160){{.*}} !alloc_token [[META_CONTAINSPTR]]
+ContainsPtr *test_new_struct_array_with_ptr() {
+ return new ContainsPtr[10];
+}
+
+class TestClass {
+public:
+ void Foo();
+ ~TestClass();
+ int data[16];
+};
+
+// CHECK-LABEL: define dso_local noundef ptr @_Z14test_new_classv(
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 64){{.*}} !alloc_token [[META_TESTCLASS:![0-9]+]]
+TestClass *test_new_class() {
+ return new TestClass();
+}
+
+// CHECK-LABEL: define dso_local noundef ptr @_Z20test_new_class_arrayv(
+// CHECK: call noalias noundef nonnull ptr @_Znam(i64 noundef 648){{.*}} !alloc_token [[META_TESTCLASS]]
+TestClass *test_new_class_array() {
+ return new TestClass[10];
+}
+
+// Test that we detect that virtual classes have implicit vtable pointer.
+class VirtualTestClass {
+public:
+ virtual void Foo();
+ virtual ~VirtualTestClass();
+ int data[16];
+};
+
+// CHECK-LABEL: define dso_local noundef ptr @_Z22test_new_virtual_classv(
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 72){{.*}} !alloc_token [[META_VIRTUALTESTCLASS:![0-9]+]]
+VirtualTestClass *test_new_virtual_class() {
+ return new VirtualTestClass();
+}
+
+// CHECK-LABEL: define dso_local noundef ptr @_Z28test_new_virtual_class_arrayv(
+// CHECK: call noalias noundef nonnull ptr @_Znam(i64 noundef 728){{.*}} !alloc_token [[META_VIRTUALTESTCLASS]]
+VirtualTestClass *test_new_virtual_class_array() {
+ return new VirtualTestClass[10];
+}
+
+// uintptr_t is treated as a pointer.
+struct MyStructUintptr {
+ int a;
+ uintptr_t ptr;
+};
+
+// CHECK-LABEL: define dso_local noundef ptr @_Z18test_uintptr_isptrv(
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 16){{.*}} !alloc_token [[META_MYSTRUCTUINTPTR:![0-9]+]]
+MyStructUintptr *test_uintptr_isptr() {
+ return new MyStructUintptr;
+}
+
+using uptr = uintptr_t;
+// CHECK-LABEL: define dso_local noundef ptr @_Z19test_uintptr_isptr2v(
+// CHECK: call noalias noundef nonnull ptr @_Znwm(i64 noundef 8){{.*}} !alloc_token [[META_UINTPTR:![0-9]+]]
+uptr *test_uintptr_isptr2() {
+ return new uptr;
+}
+
+// CHECK: [[META_INT]] = !{!"int", i1 false}
+// CHECK: [[META_ULONG]] = !{!"unsigned long", i1 false}
+// CHECK: [[META_INTPTR]] = !{!"int *", i1 true}
+// CHECK: [[META_CONTAINSPTR]] = !{!"ContainsPtr", i1 true}
+// CHECK: [[META_TESTCLASS]] = !{!"TestClass", i1 false}
+// CHECK: [[META_VIRTUALTESTCLASS]] = !{!"VirtualTestClass", i1 true}
+// CHECK: [[META_MYSTRUCTUINTPTR]] = !{!"MyStructUintptr", i1 true}
+// CHECK: [[META_UINTPTR]] = !{!"unsigned long", i1 true}
diff --git a/clang/test/CodeGenCXX/alloc-token.cpp b/clang/test/CodeGenCXX/alloc-token.cpp
index 52bad9c54fb3b..5914b4ca5ef23 100644
--- a/clang/test/CodeGenCXX/alloc-token.cpp
+++ b/clang/test/CodeGenCXX/alloc-token.cpp
@@ -137,5 +137,5 @@ TestClass *test_new_class_array() {
return arr;
}
-// CHECK: [[META_INT]] = !{!"int"}
-// CHECK: [[META_TESTCLASS]] = !{!"TestClass"}
+// CHECK: [[META_INT]] = !{!"int", i1 false}
+// CHECK: [[META_TESTCLASS]] = !{!"TestClass", i1 true}
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 6d0e82896fcea..8b6c25c58d61e 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -8588,13 +8588,14 @@ functions, and contains richer semantic information about the type of the
allocation. This information is consumed by the ``alloc-token`` pass to
instrument such calls with allocation token IDs.
-The metadata contains a string with the type of an allocation.
+The metadata contains: string with the type of an allocation, and a boolean
+denoting if the type contains a pointer.
.. code-block:: none
call ptr @malloc(i64 64), !alloc_token !0
- !0 = !{!"<type-name>"}
+ !0 = !{!"<type-name>", i1 <contains-pointer>}
Module Flags Metadata
=====================
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 71a8a3876eb5d..c9ff86b7df16b 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -5398,8 +5398,10 @@ void Verifier::visitCapturesMetadata(Instruction &I, const MDNode *Captures) {
void Verifier::visitAllocTokenMetadata(Instruction &I, MDNode *MD) {
Check(isa<CallBase>(I), "!alloc_token should only exist on calls", &I);
- Check(MD->getNumOperands() == 1, "!alloc_token must have 1 operand", MD);
+ Check(MD->getNumOperands() == 2, "!alloc_token must have 2 operands", MD);
Check(isa<MDString>(MD->getOperand(0)), "expected string", MD);
+ Check(mdconst::dyn_extract_or_null<ConstantInt>(MD->getOperand(1)),
+ "expected integer constant", MD);
}
/// verifyInstruction - Verify that an instruction is well formed.
diff --git a/llvm/lib/Transforms/Instrumentation/AllocToken.cpp b/llvm/lib/Transforms/Instrumentation/AllocToken.cpp
index 782d5a162a314..40720ae4b39ae 100644
--- a/llvm/lib/Transforms/Instrumentation/AllocToken.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AllocToken.cpp
@@ -69,19 +69,30 @@ enum class TokenMode : unsigned {
/// Token ID based on allocated type hash.
TypeHash = 2,
+
+ /// Token ID based on allocated type hash, where the top half ID-space is
+ /// reserved for types that contain pointers and the bottom half for types
+ /// that do not contain pointers.
+ TypeHashPointerSplit = 3,
};
//===--- Command-line options ---------------------------------------------===//
-cl::opt<TokenMode>
- ClMode("alloc-token-mode", cl::Hidden, cl::desc("Token assignment mode"),
- cl::init(TokenMode::TypeHash),
- cl::values(clEnumValN(TokenMode::Increment, "increment",
- "Incrementally increasing token ID"),
- clEnumValN(TokenMode::Random, "random",
- "Statically-assigned random token ID"),
- clEnumValN(TokenMode::TypeHash, "typehash",
- "Token ID based on allocated type hash")));
+cl::opt<TokenMode> ClMode(
+ "alloc-token-mode", cl::Hidden, cl::desc("Token assignment mode"),
+ cl::init(TokenMode::TypeHashPointerSplit),
+ cl::values(
+ clEnumValN(TokenMode::Increment, "increment",
+ "Incrementally increasing token ID"),
+ clEnumValN(TokenMode::Random, "random",
+ "Statically-assigned random token ID"),
+ clEnumValN(TokenMode::TypeHash, "typehash",
+ "Token ID based on allocated type hash"),
+ clEnumValN(
+ TokenMode::TypeHashPointerSplit, "typehashpointersplit",
+ "Token ID based on allocated type hash, where the top half "
+ "ID-space is reserved for types that contain pointers and the "
+ "bottom half for types that do not contain pointers. ")));
cl::opt<std::string> ClFuncPrefix("alloc-token-prefix",
cl::desc("The allocation function prefix"),
@@ -127,16 +138,23 @@ STATISTIC(NumAllocationsInstrumented, "Allocations instrumented");
/// Returns the !alloc_token metadata if available.
///
-/// Expected format is: !{<type-name>}
+/// Expected format is: !{<type-name>, <contains-pointer>}
MDNode *getAllocTokenMetadata(const CallBase &CB) {
MDNode *Ret = CB.getMetadata(LLVMContext::MD_alloc_token);
if (!Ret)
return nullptr;
- assert(Ret->getNumOperands() == 1 && "bad !alloc_token");
+ assert(Ret->getNumOperands() == 2 && "bad !alloc_token");
assert(isa<MDString>(Ret->getOperand(0)));
+ assert(isa<ConstantAsMetadata>(Ret->getOperand(1)));
return Ret;
}
+bool containsPointer(const MDNode *MD) {
+ ConstantAsMetadata *C = cast<ConstantAsMetadata>(MD->getOperand(1));
+ auto *CI = cast<ConstantInt>(C->getValue());
+ return CI->getValue().getBoolValue();
+}
+
class ModeBase {
public:
explicit ModeBase(const IntegerType &TokenTy, uint64_t MaxTokens)
@@ -188,12 +206,20 @@ class TypeHashMode : public ModeBase {
using ModeBase::ModeBase;
uint64_t operator()(const CallBase &CB, OptimizationRemarkEmitter &ORE) {
+ const auto [N, H] = getHash(CB, ORE);
+ return N ? boundedToken(H) : H;
+ }
+
+protected:
+ std::pair<MDNode *, uint64_t> getHash(const CallBase &CB,
+ OptimizationRemarkEmitter &ORE) {
if (MDNode *N = getAllocTokenMetadata(CB)) {
MDString *S = cast<MDString>(N->getOperand(0));
- return boundedToken(getStableSipHash(S->getString()));
+ return {N, getStableSipHash(S->getString())};
}
+ // Fallback.
remarkNoMetadata(CB, ORE);
- return ClFallbackToken;
+ return {nullptr, ClFallbackToken};
}
/// Remark that there was no precise type information.
@@ -210,6 +236,29 @@ class TypeHashMode : public ModeBase {
}
};
+/// Implementation for TokenMode::TypeHashPointerSplit.
+class TypeHashPointerSplitMode : public TypeHashMode {
+public:
+ using TypeHashMode::TypeHashMode;
+
+ uint64_t operator()(const CallBase &CB, OptimizationRemarkEmitter &ORE) {
+ if (MaxTokens == 1)
+ return 0;
+ const uint64_t HalfTokens = MaxTokens / 2;
+ const auto [N, H] = getHash(CB, ORE);
+ if (!N) {
+ // Pick the fallback token (ClFallbackToken), which by default is 0,
+ // meaning it'll fall into the pointer-less bucket. Override by setting
+ // -alloc-token-fallback if that is the wrong choice.
+ return H;
+ }
+ uint64_t Hash = H % HalfTokens; // base hash
+ if (containsPointer(N))
+ Hash += HalfTokens;
+ return Hash;
+ }
+};
+
// Apply opt overrides.
AllocTokenOptions transformOptionsFromCl(AllocTokenOptions Opts) {
if (!Opts.MaxTokens.has_value())
@@ -236,6 +285,9 @@ class AllocToken {
case TokenMode::TypeHash:
Mode.emplace<TypeHashMode>(*IntPtrTy, *Options.MaxTokens);
break;
+ case TokenMode::TypeHashPointerSplit:
+ Mode.emplace<TypeHashPointerSplitMode>(*IntPtrTy, *Options.MaxTokens);
+ break;
}
}
@@ -275,7 +327,9 @@ class AllocToken {
// Cache for replacement functions.
DenseMap<std::pair<LibFunc, uint64_t>, FunctionCallee> TokenAllocFunctions;
// Selected mode.
- std::variant<IncrementMode, RandomMode, TypeHashMode> Mode;
+ std::variant<IncrementMode, RandomMode, TypeHashMode,
+ TypeHashPointerSplitMode>
+ Mode;
};
bool AllocToken::instrumentFunction(Function &F) {
diff --git a/llvm/test/Instrumentation/AllocToken/extralibfuncs.ll b/llvm/test/Instrumentation/AllocToken/extralibfuncs.ll
index 5f08552c789f3..0e382b2cebed6 100644
--- a/llvm/test/Instrumentation/AllocToken/extralibfuncs.ll
+++ b/llvm/test/Instrumentation/AllocToken/extralibfuncs.ll
@@ -38,7 +38,7 @@ entry:
ret ptr %ptr1
}
-!0 = !{!"int"}
+!0 = !{!"int", i1 0}
;.
-; CHECK: [[META0]] = !{!"int"}
+; CHECK: [[META0]] = !{!"int", i1 false}
;.
diff --git a/llvm/test/Instrumentation/AllocToken/nonlibcalls.ll b/llvm/test/Instrumentation/AllocToken/nonlibcalls.ll
index e023ab6b11b1e..19673da1bcfb6 100644
--- a/llvm/test/Instrumentation/AllocToken/nonlibcalls.ll
+++ b/llvm/test/Instrumentation/AllocToken/nonlibcalls.ll
@@ -79,7 +79,7 @@ entry:
ret ptr %ptr1
}
-!0 = !{!"int"}
+!0 = !{!"int", i1 0}
;.
-; CHECK: [[META0]] = !{!"int"}
+; CHECK: [[META0]] = !{!"int", i1 false}
;.
diff --git a/llvm/test/Instrumentation/AllocToken/remark.ll b/llvm/test/Instrumentation/AllocToken/remark.ll
index a2404526ea53f..f2eaa6209d89e 100644
--- a/llvm/test/Instrumentation/AllocToken/remark.ll
+++ b/llvm/test/Instrumentation/AllocToken/remark.ll
@@ -32,7 +32,7 @@ entry:
ret ptr %ptr1
}
-!0 = !{!"int"}
+!0 = !{!"int", i1 0}
;.
-; CHECK: [[META0]] = !{!"int"}
+; CHECK: [[META0]] = !{!"int", i1 false}
;.
diff --git a/llvm/test/Instrumentation/AllocToken/typehashpointersplit.ll b/llvm/test/Instrumentation/AllocToken/typehashpointersplit.ll
new file mode 100644
index 0000000000000..1f776480c5b3a
--- /dev/null
+++ b/llvm/test/Instrumentation/AllocToken/typehashpointersplit.ll
@@ -0,0 +1,35 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=inferattrs,alloc-token -alloc-token-mode=typehashpointersplit -alloc-token-max=2 -S | FileCheck %s
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+
+declare ptr @malloc(i64)
+
+define void @test_typehashpointersplit() sanitize_alloc_token {
+; CHECK-LABEL: define void @test_typehashpointersplit(
+; CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = call ptr @__alloc_token_malloc(i64 4, i64 0), !alloc_token [[META0:![0-9]+]]
+; CHECK-NEXT: [[TMP1:%.*]] = call ptr @__alloc_token_malloc(i64 128, i64 0), !alloc_token [[META1:![0-9]+]]
+; CHECK-NEXT: [[TMP2:%.*]] = call ptr @__alloc_token_malloc(i64 8, i64 1), !alloc_token [[META2:![0-9]+]]
+; CHECK-NEXT: [[TMP3:%.*]] = call ptr @__alloc_token_malloc(i64 64, i64 1), !alloc_token [[META3:![0-9]+]]
+; CHECK-NEXT: ret void
+;
+entry:
+ call ptr @malloc(i64 4), !alloc_token !0
+ call ptr @malloc(i64 128), !alloc_token !1
+ call ptr @malloc(i64 8), !alloc_token !2
+ call ptr @malloc(i64 64), !alloc_token !3
+ ret void
+}
+
+!0 = !{!"int", i1 0}
+!1 = !{!"Foo", i1 0}
+!2 = !{!"int*", i1 1}
+!3 = !{!"Foo", i1 1}
+;.
+; CHECK: [[META0]] = !{!"int", i1 false}
+; CHECK: [[META1]] = !{!"Foo", i1 false}
+; CHECK: [[META2]] = !{!"int*", i1 true}
+; CHECK: [[META3]] = !{!"Foo", i1 true}
+;.
diff --git a/llvm/test/Transforms/SimplifyCFG/merge-calls-alloc-token.ll b/llvm/test/Transforms/SimplifyCFG/merge-calls-alloc-token.ll
index 9bbe3eb371673..42d3dcc92712d 100644
--- a/llvm/test/Transforms/SimplifyCFG/merge-calls-alloc-token.ll
+++ b/llvm/test/Transforms/SimplifyCFG/merge-calls-alloc-token.ll
@@ -97,8 +97,8 @@ if.end:
ret ptr %x.0
}
-!0 = !{!"int"}
-!1 = !{!"char[4]"}
+!0 = !{!"int", i1 0}
+!1 = !{!"char[4]", i1 0}
;.
-; CHECK: [[META0]] = !{!"int"}
+; CHECK: [[META0]] = !{!"int", i1 false}
;.
More information about the llvm-commits
mailing list