Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions clang/docs/AllocToken.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ The default mode to calculate tokens is:
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>``:
change or removal. These may (experimentally) be selected with ``-Xclang
-falloc-token-mode=<mode>``:

* ``typehash``: This mode assigns a token ID based on the hash of the allocated
type's name.
Expand Down
4 changes: 0 additions & 4 deletions clang/include/clang/Basic/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -447,10 +447,6 @@ class CodeGenOptions : public CodeGenOptionsBase {

std::optional<double> AllowRuntimeCheckSkipHotCutoff;

/// Maximum number of allocation tokens (0 = no max), nullopt if none set (use
/// pass default).
std::optional<uint64_t> AllocTokenMax;

/// List of backend command-line options for -fembed-bitcode.
std::vector<uint8_t> CmdArgs;

Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "llvm/ADT/FloatingPointMode.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/DXContainer.h"
#include "llvm/Support/AllocToken.h"
#include "llvm/TargetParser/Triple.h"
#include <optional>
#include <string>
Expand Down Expand Up @@ -565,6 +566,13 @@ class LangOptions : public LangOptionsBase {
bool AtomicFineGrainedMemory = false;
bool AtomicIgnoreDenormalMode = false;

/// Maximum number of allocation tokens (0 = no max), nullopt if none set (use
/// target default).
std::optional<uint64_t> AllocTokenMax;

/// The allocation token mode.
std::optional<llvm::AllocTokenMode> AllocTokenMode;

LangOptions();

/// Set language defaults for the given input language and
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -2751,6 +2751,10 @@ def falloc_token_max_EQ : Joined<["-"], "falloc-token-max=">,
MetaVarName<"<N>">,
HelpText<"Limit to maximum N allocation tokens (0 = no max)">;

def falloc_token_mode_EQ : Joined<["-"], "falloc-token-mode=">,
Group<f_Group>, Visibility<[CC1Option]>,
HelpText<"Set the allocation token mode (experimental)">;

def fallow_runtime_check_skip_hot_cutoff_EQ
: Joined<["-"], "fallow-runtime-check-skip-hot-cutoff=">,
Group<f_clang_Group>,
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,12 @@ class EmitAssemblyHelper {
};
} // namespace

static AllocTokenOptions getAllocTokenOptions(const CodeGenOptions &CGOpts) {
static AllocTokenOptions getAllocTokenOptions(const LangOptions &LangOpts,
const CodeGenOptions &CGOpts) {
AllocTokenOptions Opts;
Opts.MaxTokens = CGOpts.AllocTokenMax;
if (LangOpts.AllocTokenMode)
Opts.Mode = *LangOpts.AllocTokenMode;
Opts.MaxTokens = LangOpts.AllocTokenMax;
Opts.Extended = CGOpts.SanitizeAllocTokenExtended;
Opts.FastABI = CGOpts.SanitizeAllocTokenFastABI;
return Opts;
Expand Down Expand Up @@ -808,7 +811,7 @@ static void addSanitizers(const Triple &TargetTriple,
// memory allocation function detection.
MPM.addPass(InferFunctionAttrsPass());
}
MPM.addPass(AllocTokenPass(getAllocTokenOptions(CodeGenOpts)));
MPM.addPass(AllocTokenPass(getAllocTokenOptions(LangOpts, CodeGenOpts)));
}
};
if (ClSanitizeOnOptimizerEarlyEP) {
Expand Down
60 changes: 47 additions & 13 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1833,10 +1833,6 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
serializeSanitizerKinds(Opts.SanitizeAnnotateDebugInfo))
GenerateArg(Consumer, OPT_fsanitize_annotate_debug_info_EQ, Sanitizer);

if (Opts.AllocTokenMax)
GenerateArg(Consumer, OPT_falloc_token_max_EQ,
std::to_string(*Opts.AllocTokenMax));

if (!Opts.EmitVersionIdentMetadata)
GenerateArg(Consumer, OPT_Qn);

Expand Down Expand Up @@ -2350,15 +2346,6 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
}
}

if (const auto *Arg = Args.getLastArg(options::OPT_falloc_token_max_EQ)) {
StringRef S = Arg->getValue();
uint64_t Value = 0;
if (S.getAsInteger(0, Value))
Diags.Report(diag::err_drv_invalid_value) << Arg->getAsString(Args) << S;
else
Opts.AllocTokenMax = Value;
}

Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);

if (!LangOpts->CUDAIsDevice)
Expand Down Expand Up @@ -3966,6 +3953,29 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,

if (!Opts.RandstructSeed.empty())
GenerateArg(Consumer, OPT_frandomize_layout_seed_EQ, Opts.RandstructSeed);

if (Opts.AllocTokenMax)
GenerateArg(Consumer, OPT_falloc_token_max_EQ,
std::to_string(*Opts.AllocTokenMax));

if (Opts.AllocTokenMode) {
StringRef S;
switch (*Opts.AllocTokenMode) {
case llvm::AllocTokenMode::Increment:
S = "increment";
break;
case llvm::AllocTokenMode::Random:
S = "random";
break;
case llvm::AllocTokenMode::TypeHash:
S = "typehash";
break;
case llvm::AllocTokenMode::TypeHashPointerSplit:
S = "typehashpointersplit";
break;
}
GenerateArg(Consumer, OPT_falloc_token_mode_EQ, S);
}
}

bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
Expand Down Expand Up @@ -4544,6 +4554,30 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
if (const Arg *A = Args.getLastArg(OPT_frandomize_layout_seed_EQ))
Opts.RandstructSeed = A->getValue(0);

if (const auto *Arg = Args.getLastArg(options::OPT_falloc_token_max_EQ)) {
StringRef S = Arg->getValue();
uint64_t Value = 0;
if (S.getAsInteger(0, Value))
Diags.Report(diag::err_drv_invalid_value) << Arg->getAsString(Args) << S;
else
Opts.AllocTokenMax = Value;
}

if (const auto *Arg = Args.getLastArg(options::OPT_falloc_token_mode_EQ)) {
StringRef S = Arg->getValue();
auto Mode = llvm::StringSwitch<std::optional<llvm::AllocTokenMode>>(S)
.Case("increment", llvm::AllocTokenMode::Increment)
.Case("random", llvm::AllocTokenMode::Random)
.Case("typehash", llvm::AllocTokenMode::TypeHash)
.Case("typehashpointersplit",
llvm::AllocTokenMode::TypeHashPointerSplit)
.Default(std::nullopt);
if (Mode)
Opts.AllocTokenMode = Mode;
else
Diags.Report(diag::err_drv_invalid_value) << Arg->getAsString(Args) << S;
}

// Validate options for HLSL
if (Opts.HLSL) {
// TODO: Revisit restricting SPIR-V to logical once we've figured out how to
Expand Down
11 changes: 11 additions & 0 deletions clang/test/Driver/fsanitize-alloc-token.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,14 @@
// CHECK-MAX: "-falloc-token-max=42"
// RUN: not %clang --target=x86_64-linux-gnu -fsanitize=alloc-token -falloc-token-max=-1 %s 2>&1 | FileCheck -check-prefix=CHECK-INVALID-MAX %s
// CHECK-INVALID-MAX: error: invalid value

// RUN: %clang --target=x86_64-linux-gnu -Xclang -falloc-token-mode=increment %s -### 2>&1 | FileCheck -check-prefix=CHECK-MODE-INCREMENT %s
// CHECK-MODE-INCREMENT: "-falloc-token-mode=increment"
// RUN: %clang --target=x86_64-linux-gnu -Xclang -falloc-token-mode=random %s -### 2>&1 | FileCheck -check-prefix=CHECK-MODE-RANDOM %s
// CHECK-MODE-RANDOM: "-falloc-token-mode=random"
// RUN: %clang --target=x86_64-linux-gnu -Xclang -falloc-token-mode=typehash %s -### 2>&1 | FileCheck -check-prefix=CHECK-MODE-TYPEHASH %s
// CHECK-MODE-TYPEHASH: "-falloc-token-mode=typehash"
// RUN: %clang --target=x86_64-linux-gnu -Xclang -falloc-token-mode=typehashpointersplit %s -### 2>&1 | FileCheck -check-prefix=CHECK-MODE-TYPEHASHPTRSPLIT %s
// CHECK-MODE-TYPEHASHPTRSPLIT: "-falloc-token-mode=typehashpointersplit"
// RUN: not %clang --target=x86_64-linux-gnu -Xclang -falloc-token-mode=asdf %s 2>&1 | FileCheck -check-prefix=CHECK-INVALID-MODE %s
// CHECK-INVALID-MODE: error: invalid value 'asdf'
8 changes: 8 additions & 0 deletions llvm/include/llvm/IR/Intrinsics.td
Original file line number Diff line number Diff line change
Expand Up @@ -2853,7 +2853,15 @@ def int_ptrauth_blend :
def int_ptrauth_sign_generic :
DefaultAttrsIntrinsic<[llvm_i64_ty], [llvm_i64_ty, llvm_i64_ty], [IntrNoMem]>;

//===----------------- AllocToken Intrinsics ------------------------------===//

// Return the token ID for the given !alloc_token metadata.
def int_alloc_token_id :
DefaultAttrsIntrinsic<[llvm_anyint_ty], [llvm_metadata_ty],
[IntrNoMem, NoUndef<RetIndex>]>;

//===----------------------------------------------------------------------===//

//===------- Convergence Intrinsics ---------------------------------------===//

def int_experimental_convergence_entry
Expand Down
62 changes: 62 additions & 0 deletions llvm/include/llvm/Support/AllocToken.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//===- llvm/Support/AllocToken.h - Allocation Token Calculation -----*- C++ -*//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Definition of AllocToken modes and shared calculation of stateless token IDs.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_ALLOCTOKEN_H
#define LLVM_SUPPORT_ALLOCTOKEN_H

#include "llvm/ADT/SmallString.h"
#include <cstdint>
#include <optional>

namespace llvm {

/// Modes for generating allocation token IDs.
enum class AllocTokenMode {
/// Incrementally increasing token ID.
Increment,

/// Simple mode that returns a statically-assigned random token ID.
Random,

/// Token ID based on allocated type hash.
TypeHash,

/// 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,
};

/// The default allocation token mode.
inline constexpr AllocTokenMode DefaultAllocTokenMode =
AllocTokenMode::TypeHashPointerSplit;

/// Metadata about an allocation used to generate a token ID.
struct AllocTokenMetadata {
SmallString<64> TypeName;
bool ContainsPointer;
};

/// Calculates stable allocation token ID. Returns std::nullopt for stateful
/// modes that are only available in the AllocToken pass.
///
/// \param Mode The token generation mode.
/// \param Metadata The metadata about the allocation.
/// \param MaxTokens The maximum number of tokens (must not be 0)
/// \return The calculated allocation token ID, or std::nullopt.
std::optional<uint64_t> getAllocTokenHash(AllocTokenMode Mode,
const AllocTokenMetadata &Metadata,
uint64_t MaxTokens);

} // end namespace llvm

#endif // LLVM_SUPPORT_ALLOCTOKEN_H
2 changes: 2 additions & 0 deletions llvm/include/llvm/Transforms/Instrumentation/AllocToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@

#include "llvm/IR/Analysis.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Support/AllocToken.h"
#include <optional>

namespace llvm {

class Module;

struct AllocTokenOptions {
AllocTokenMode Mode = DefaultAllocTokenMode;
std::optional<uint64_t> MaxTokens;
bool FastABI = false;
bool Extended = false;
Expand Down
32 changes: 32 additions & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,38 @@ Expected<MemorySanitizerOptions> parseMSanPassOptions(StringRef Params) {
return Result;
}

Expected<AllocTokenOptions> parseAllocTokenPassOptions(StringRef Params) {
AllocTokenOptions Result;
while (!Params.empty()) {
StringRef ParamName;
std::tie(ParamName, Params) = Params.split(';');

if (ParamName.consume_front("mode=")) {
auto Mode = StringSwitch<std::optional<AllocTokenMode>>(ParamName)
.Case("increment", AllocTokenMode::Increment)
.Case("random", AllocTokenMode::Random)
.Case("typehash", AllocTokenMode::TypeHash)
.Case("typehashpointersplit",
AllocTokenMode::TypeHashPointerSplit)
.Default(std::nullopt);
if (Mode)
Result.Mode = *Mode;
else
return make_error<StringError>(
formatv("invalid argument to AllocToken pass mode "
"parameter: '{}'",
ParamName)
.str(),
inconvertibleErrorCode());
} else {
return make_error<StringError>(
formatv("invalid AllocToken pass parameter '{}'", ParamName).str(),
inconvertibleErrorCode());
}
}
return Result;
}

/// Parser of parameters for SimplifyCFG pass.
Expected<SimplifyCFGOptions> parseSimplifyCFGOptions(StringRef Params) {
SimplifyCFGOptions Result;
Expand Down
5 changes: 4 additions & 1 deletion llvm/lib/Passes/PassRegistry.def
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ MODULE_PASS("openmp-opt", OpenMPOptPass())
MODULE_PASS("openmp-opt-postlink",
OpenMPOptPass(ThinOrFullLTOPhase::FullLTOPostLink))
MODULE_PASS("partial-inliner", PartialInlinerPass())
MODULE_PASS("alloc-token", AllocTokenPass())
MODULE_PASS("pgo-icall-prom", PGOIndirectCallPromotion())
MODULE_PASS("pgo-instr-gen", PGOInstrumentationGen())
MODULE_PASS("pgo-instr-use", PGOInstrumentationUse())
Expand Down Expand Up @@ -181,6 +180,10 @@ MODULE_PASS("wholeprogramdevirt", WholeProgramDevirtPass())
#ifndef MODULE_PASS_WITH_PARAMS
#define MODULE_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)
#endif
MODULE_PASS_WITH_PARAMS(
"alloc-token", "AllocTokenPass",
[](AllocTokenOptions Opts) { return AllocTokenPass(Opts); },
parseAllocTokenPassOptions, "mode=<mode>")
MODULE_PASS_WITH_PARAMS(
"asan", "AddressSanitizerPass",
[](AddressSanitizerOptions Opts) { return AddressSanitizerPass(Opts); },
Expand Down
46 changes: 46 additions & 0 deletions llvm/lib/Support/AllocToken.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===- AllocToken.cpp - Allocation Token Calculation ----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Definition of AllocToken modes and shared calculation of stateless token IDs.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/AllocToken.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SipHash.h"

namespace llvm {
std::optional<uint64_t> getAllocTokenHash(AllocTokenMode Mode,
const AllocTokenMetadata &Metadata,
uint64_t MaxTokens) {
assert(MaxTokens && "Must provide concrete max tokens");

switch (Mode) {
case AllocTokenMode::Increment:
case AllocTokenMode::Random:
// Stateful modes cannot be implemented as a pure function.
return std::nullopt;

case AllocTokenMode::TypeHash: {
return getStableSipHash(Metadata.TypeName) % MaxTokens;
}

case AllocTokenMode::TypeHashPointerSplit: {
if (MaxTokens == 1)
return 0;
const uint64_t HalfTokens = MaxTokens / 2;
uint64_t Hash = getStableSipHash(Metadata.TypeName) % HalfTokens;
if (Metadata.ContainsPointer)
Hash += HalfTokens;
return Hash;
}
}

llvm_unreachable("");
}
} // namespace llvm
1 change: 1 addition & 0 deletions llvm/lib/Support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ add_llvm_component_library(LLVMSupport
AArch64BuildAttributes.cpp
ARMAttributeParser.cpp
ARMWinEH.cpp
AllocToken.cpp
Allocator.cpp
AutoConvert.cpp
Base64.cpp
Expand Down
Loading
Loading