Skip to content

Commit 3d53b52

Browse files
committed
[SanitizerBinaryMetadata] Optimize used space for features and UAR stack args
Optimize the encoding of "covered" metadata by: 1. Reducing feature mask from 4 bytes to 1 byte (needs increase once we reach more than 8 features). 2. Only emitting UAR stack args size if it is non-zero, saving 4 bytes in the common case. One caveat is that the emitted metadata for function PC (offset), size, and UAR size (if enabled) are no longer aligned to 4 bytes. SanitizerBinaryMetadata version base is increased to 2, since the change is backwards incompatible. Reviewed By: dvyukov Differential Revision: https://reviews.llvm.org/D143482
1 parent 938fdfc commit 3d53b52

File tree

9 files changed

+80
-42
lines changed

9 files changed

+80
-42
lines changed

clang/test/CodeGen/sanitize-metadata.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ int atomics() {
2222
return y;
2323
}
2424
// ATOMICS-LABEL: __sanitizer_metadata_atomics.module_ctor
25-
// ATOMICS: call void @__sanitizer_metadata_atomics_add(i32 1, ptr @__start_sanmd_atomics, ptr @__stop_sanmd_atomics)
25+
// ATOMICS: call void @__sanitizer_metadata_atomics_add(i32 2, ptr @__start_sanmd_atomics, ptr @__stop_sanmd_atomics)
2626
// ATOMICS-LABEL: __sanitizer_metadata_atomics.module_dtor
27-
// ATOMICS: call void @__sanitizer_metadata_atomics_del(i32 1, ptr @__start_sanmd_atomics, ptr @__stop_sanmd_atomics)
27+
// ATOMICS: call void @__sanitizer_metadata_atomics_del(i32 2, ptr @__start_sanmd_atomics, ptr @__stop_sanmd_atomics)
2828

2929
// CHECK-LABEL: __sanitizer_metadata_covered.module_ctor
30-
// CHECK: call void @__sanitizer_metadata_covered_add(i32 1, ptr @__start_sanmd_covered, ptr @__stop_sanmd_covered)
30+
// CHECK: call void @__sanitizer_metadata_covered_add(i32 2, ptr @__start_sanmd_covered, ptr @__stop_sanmd_covered)
3131
// CHECK-LABEL: __sanitizer_metadata_covered.module_dtor
32-
// CHECK: call void @__sanitizer_metadata_covered_del(i32 1, ptr @__start_sanmd_covered, ptr @__stop_sanmd_covered)
32+
// CHECK: call void @__sanitizer_metadata_covered_del(i32 2, ptr @__start_sanmd_covered, ptr @__stop_sanmd_covered)
3333

3434
// ATOMICS: ![[ATOMICS_COVERED]] = !{!"sanmd_covered", ![[ATOMICS_COVERED_AUX:[0-9]+]]}
35-
// ATOMICS: ![[ATOMICS_COVERED_AUX]] = !{i32 1}
35+
// ATOMICS: ![[ATOMICS_COVERED_AUX]] = !{i8 1}
3636
// ATOMICS: ![[ATOMIC_OP]] = !{!"sanmd_atomics"}

compiler-rt/test/metadata/common.h

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,54 @@
11
#include <assert.h>
22
#include <stdint.h>
33
#include <stdio.h>
4+
#include <string.h>
45

56
int main() { printf("main\n"); }
67

7-
typedef unsigned long uptr;
8-
8+
namespace {
99
#define FN(X) \
10-
if (pc == reinterpret_cast<uptr>(X)) \
10+
if (pc == reinterpret_cast<uintptr_t>(X)) \
1111
return #X
1212

13-
const char *symbolize(uptr pc) {
13+
const char *symbolize(uintptr_t pc) {
1414
FUNCTIONS;
1515
return nullptr;
1616
}
1717

1818
template <typename T> T consume(const char *&pos, const char *end) {
19-
T v = *reinterpret_cast<const T *>(pos);
19+
T v;
20+
// We need to memcpy from pos, because it's not guaranteed that every entry
21+
// has the required alignment of T.
22+
memcpy(&v, pos, sizeof(T));
2023
pos += sizeof(T);
2124
assert(pos <= end);
2225
return v;
2326
}
2427

28+
constexpr uint32_t kSanitizerBinaryMetadataUARHasSize = 1 << 2;
29+
2530
uint32_t meta_version;
2631
const char *meta_start;
2732
const char *meta_end;
33+
const char *atomics_start;
34+
const char *atomics_end;
35+
}; // namespace
2836

2937
extern "C" {
3038
void __sanitizer_metadata_covered_add(uint32_t version, const char *start,
3139
const char *end) {
32-
printf("metadata add version %u\n", version);
40+
const uint32_t version_base = version & 0xffff;
41+
const bool offset_ptr_sized = version & (1 << 16);
42+
assert(version_base == 2);
43+
printf("metadata add version %u\n", version_base);
3344
for (const char *pos = start; pos < end;) {
34-
const uptr base = reinterpret_cast<uptr>(pos);
35-
const long offset = (version & (1 << 16)) ? consume<long>(pos, end)
36-
: consume<int>(pos, end);
37-
const uint32_t size = consume<uint32_t>(pos, end);
38-
const uint32_t features = consume<uint32_t>(pos, end);
45+
const auto base = reinterpret_cast<uintptr_t>(pos);
46+
const intptr_t offset = offset_ptr_sized ? consume<intptr_t>(pos, end)
47+
: consume<int32_t>(pos, end);
48+
[[maybe_unused]] const uint32_t size = consume<uint32_t>(pos, end);
49+
const uint32_t features = consume<uint8_t>(pos, end);
3950
uint32_t stack_args = 0;
40-
if (features & (1 << 1))
51+
if (features & kSanitizerBinaryMetadataUARHasSize)
4152
stack_args = consume<uint32_t>(pos, end);
4253
if (const char *name = symbolize(base + offset))
4354
printf("%s: features=%x stack_args=%u\n", name, features, stack_args);
@@ -54,9 +65,6 @@ void __sanitizer_metadata_covered_del(uint32_t version, const char *start,
5465
assert(end == meta_end);
5566
}
5667

57-
const char *atomics_start;
58-
const char *atomics_end;
59-
6068
void __sanitizer_metadata_atomics_add(uint32_t version, const char *start,
6169
const char *end) {
6270
assert(version == meta_version);

compiler-rt/test/metadata/covered.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
// RUN: %clangxx %s -o %t -fexperimental-sanitize-metadata=covered,uar && %t | FileCheck -check-prefix=CHECK-CU %s
77
// RUN: %clangxx %s -o %t -fexperimental-sanitize-metadata=atomics,uar && %t | FileCheck -check-prefix=CHECK-AU %s
88
// RUN: %clangxx %s -o %t -fexperimental-sanitize-metadata=covered,atomics,uar && %t | FileCheck -check-prefix=CHECK-CAU %s
9+
// RUN: %clangxx %s -o %t -mcmodel=large -fexperimental-sanitize-metadata=covered,atomics,uar && %t | FileCheck -check-prefix=CHECK-CAU %s
910

1011
const int const_global = 42;
1112

1213
__attribute__((noinline, not_tail_called)) void escape(const volatile void *p) {
13-
static const volatile void *sink;
14+
[[maybe_unused]] static const volatile void *sink;
1415
sink = p;
1516
}
1617

@@ -69,6 +70,20 @@ int with_atomic_escape(int *p) {
6970
return __atomic_load_n(p, __ATOMIC_RELAXED);
7071
}
7172

73+
// CHECK-C: with_atomic_escape_lots_of_args: features=0
74+
// CHECK-A: with_atomic_escape_lots_of_args: features=1
75+
// CHECK-U: with_atomic_escape_lots_of_args: features=6
76+
// CHECK-CA: with_atomic_escape_lots_of_args: features=1
77+
// CHECK-CU: with_atomic_escape_lots_of_args: features=6
78+
// CHECK-AU: with_atomic_escape_lots_of_args: features=7
79+
// CHECK-CAU: with_atomic_escape_lots_of_args: features=7
80+
long with_atomic_escape_lots_of_args(int *p, long a0, long a1, long a2, long a3,
81+
long a4, long a5, long a6) {
82+
escape(&p);
83+
return a0 + a1 + a2 + a3 + a4 + a5 + a6 +
84+
__atomic_load_n(p, __ATOMIC_RELAXED);
85+
}
86+
7287
// CHECK-C: ellipsis: features=0
7388
// CHECK-A: ellipsis: features=1
7489
// CHECK-U-NOT: ellipsis:
@@ -78,7 +93,7 @@ int with_atomic_escape(int *p) {
7893
// CHECK-CAU: ellipsis: features=1
7994
void ellipsis(int *p, ...) {
8095
escape(&p);
81-
volatile int x;
96+
[[maybe_unused]] volatile int x;
8297
x = 0;
8398
}
8499

@@ -100,6 +115,7 @@ int ellipsis_with_atomic(int *p, ...) {
100115
FN(with_const_global); \
101116
FN(with_atomic); \
102117
FN(with_atomic_escape); \
118+
FN(with_atomic_escape_lots_of_args); \
103119
FN(ellipsis); \
104120
FN(ellipsis_with_atomic); \
105121
/**/

compiler-rt/test/metadata/lit.site.cfg.py.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configu
1111
# Load tool-specific config that would do the real work.
1212
lit_config.load_config(config, "@METADATA_LIT_SOURCE_DIR@/lit.cfg.py")
1313

14-
config.substitutions.append(("%clangxx ", " " + config.clang + " " + config.target_cflags + " "))
14+
clangxx = [config.clang] + config.cxx_mode_flags + ["-Wall", config.target_cflags]
15+
config.substitutions.append(("%clangxx ", " ".join([""] + clangxx + [""])))

compiler-rt/test/metadata/uar.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
// RUN: %clangxx %s -O1 -o %t -fexperimental-sanitize-metadata=covered,uar && %t | FileCheck %s
2-
// RUN: %clangxx %s -O1 -o %t -fexperimental-sanitize-metadata=covered,uar -fsanitize=address,signed-integer-overflow && %t | FileCheck %s
2+
// RUN: %clangxx %s -O1 -o %t -fexperimental-sanitize-metadata=covered,uar -fsanitize=address,signed-integer-overflow,alignment && %t | FileCheck %s
3+
// RUN: %clangxx %s -O1 -o %t -mcmodel=large -fexperimental-sanitize-metadata=covered,uar -fsanitize=address,signed-integer-overflow,alignment && %t | FileCheck %s
34

4-
// CHECK: metadata add version 1
5+
// CHECK: metadata add version 2
56

67
__attribute__((noinline, not_tail_called)) void escape(const volatile void *p) {
7-
static const volatile void *sink;
8+
[[maybe_unused]] static const volatile void *sink;
89
sink = p;
910
}
1011

@@ -44,20 +45,20 @@ void no_stack_args(long a0, long a1, long a2, long a3, long a4, long a5) {
4445
escape(&x);
4546
}
4647

47-
// CHECK: stack_args: features=2 stack_args=16
48+
// CHECK: stack_args: features=6 stack_args=16
4849
void stack_args(long a0, long a1, long a2, long a3, long a4, long a5, long a6) {
4950
int x;
5051
escape(&x);
5152
}
5253

53-
// CHECK: more_stack_args: features=2 stack_args=32
54+
// CHECK: more_stack_args: features=6 stack_args=32
5455
void more_stack_args(long a0, long a1, long a2, long a3, long a4, long a5,
5556
long a6, long a7, long a8) {
5657
int x;
5758
escape(&x);
5859
}
5960

60-
// CHECK: struct_stack_args: features=2 stack_args=144
61+
// CHECK: struct_stack_args: features=6 stack_args=144
6162
struct large {
6263
char x[131];
6364
};

llvm/include/llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ struct SanitizerBinaryMetadataOptions {
2828

2929
inline constexpr int kSanitizerBinaryMetadataAtomicsBit = 0;
3030
inline constexpr int kSanitizerBinaryMetadataUARBit = 1;
31+
inline constexpr int kSanitizerBinaryMetadataUARHasSizeBit = 2;
3132

3233
inline constexpr uint32_t kSanitizerBinaryMetadataAtomics =
3334
1 << kSanitizerBinaryMetadataAtomicsBit;
3435
inline constexpr uint32_t kSanitizerBinaryMetadataUAR =
3536
1 << kSanitizerBinaryMetadataUARBit;
37+
inline constexpr uint32_t kSanitizerBinaryMetadataUARHasSize =
38+
1 << kSanitizerBinaryMetadataUARHasSizeBit;
3639

3740
inline constexpr char kSanitizerBinaryMetadataCoveredSection[] =
3841
"sanmd_covered";

llvm/lib/CodeGen/SanitizerBinaryMetadata.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ bool MachineSanitizerBinaryMetadata::runOnMachineFunction(MachineFunction &MF) {
5757
auto &AuxMDs = *cast<MDTuple>(MD->getOperand(1));
5858
// Assume it currently only has features.
5959
assert(AuxMDs.getNumOperands() == 1);
60-
auto *Features = cast<ConstantAsMetadata>(AuxMDs.getOperand(0))->getValue();
60+
Constant *Features =
61+
cast<ConstantAsMetadata>(AuxMDs.getOperand(0))->getValue();
6162
if (!Features->getUniqueInteger()[kSanitizerBinaryMetadataUARBit])
6263
return false;
6364
// Calculate size of stack args for the function.
@@ -69,12 +70,18 @@ bool MachineSanitizerBinaryMetadata::runOnMachineFunction(MachineFunction &MF) {
6970
Align = std::max(Align, MFI.getObjectAlign(i).value());
7071
}
7172
Size = (Size + Align - 1) & ~(Align - 1);
73+
if (!Size)
74+
return false;
75+
// Non-zero size, update metadata.
7276
auto &F = MF.getFunction();
7377
IRBuilder<> IRB(F.getContext());
7478
MDBuilder MDB(F.getContext());
7579
// Keep the features and append size of stack args to the metadata.
76-
F.setMetadata(LLVMContext::MD_pcsections,
77-
MDB.createPCSections(
78-
{{Section.getString(), {Features, IRB.getInt32(Size)}}}));
80+
APInt NewFeatures = Features->getUniqueInteger();
81+
NewFeatures.setBit(kSanitizerBinaryMetadataUARHasSizeBit);
82+
F.setMetadata(
83+
LLVMContext::MD_pcsections,
84+
MDB.createPCSections({{Section.getString(),
85+
{IRB.getInt(NewFeatures), IRB.getInt32(Size)}}}));
7986
return false;
8087
}

llvm/lib/Transforms/Instrumentation/SanitizerBinaryMetadata.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
#include <array>
4545
#include <cstdint>
46+
#include <limits>
4647

4748
using namespace llvm;
4849

@@ -52,7 +53,7 @@ namespace {
5253

5354
//===--- Constants --------------------------------------------------------===//
5455

55-
constexpr uint32_t kVersionBase = 1; // occupies lower 16 bits
56+
constexpr uint32_t kVersionBase = 2; // occupies lower 16 bits
5657
constexpr uint32_t kVersionPtrSizeRel = (1u << 16); // offsets are pointer-sized
5758
constexpr int kCtorDtorPriority = 2;
5859

@@ -269,9 +270,10 @@ void SanitizerBinaryMetadata::runOn(Function &F, MetadataInfoSet &MIS) {
269270
const auto *MI = &MetadataInfo::Covered;
270271
MIS.insert(MI);
271272
const StringRef Section = getSectionName(MI->SectionSuffix);
272-
// The feature mask will be placed after the size (32 bit) of the function,
273-
// so in total one covered entry will use `sizeof(void*) + 4 + 4`.
274-
Constant *CFM = IRB.getInt32(FeatureMask);
273+
// The feature mask will be placed after the size of the function.
274+
assert(FeatureMask <= std::numeric_limits<uint8_t>::max() &&
275+
"Increase feature mask bytes and bump version");
276+
Constant *CFM = IRB.getInt8(FeatureMask);
275277
F.setMetadata(LLVMContext::MD_pcsections,
276278
MDB.createPCSections({{Section, {CFM}}}));
277279
}

llvm/test/Instrumentation/SanitizerBinaryMetadata/atomics.ll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,7 +2039,7 @@ entry:
20392039
; CHECK-DAG: entry:
20402040
; CHECK-NEXT: br i1 icmp ne (ptr @__sanitizer_metadata_atomics_add, ptr null), label %callfunc, label %ret
20412041
; CHECK-DAG: callfunc:
2042-
; CHECK-NEXT: call void @__sanitizer_metadata_atomics_add(i32 1, ptr @__start_sanmd_atomics, ptr @__stop_sanmd_atomics)
2042+
; CHECK-NEXT: call void @__sanitizer_metadata_atomics_add(i32 2, ptr @__start_sanmd_atomics, ptr @__stop_sanmd_atomics)
20432043
; CHECK-NEXT: br label %ret
20442044
; CHECK-DAG: ret:
20452045
; CHECK-NEXT: ret void
@@ -2048,7 +2048,7 @@ entry:
20482048
; CHECK-DAG: entry:
20492049
; CHECK-NEXT: br i1 icmp ne (ptr @__sanitizer_metadata_atomics_del, ptr null), label %callfunc, label %ret
20502050
; CHECK-DAG: callfunc:
2051-
; CHECK-NEXT: call void @__sanitizer_metadata_atomics_del(i32 1, ptr @__start_sanmd_atomics, ptr @__stop_sanmd_atomics)
2051+
; CHECK-NEXT: call void @__sanitizer_metadata_atomics_del(i32 2, ptr @__start_sanmd_atomics, ptr @__stop_sanmd_atomics)
20522052
; CHECK-NEXT: br label %ret
20532053
; CHECK-DAG: ret:
20542054
; CHECK-NEXT: ret void
@@ -2057,7 +2057,7 @@ entry:
20572057
; CHECK-DAG: entry:
20582058
; CHECK-NEXT: br i1 icmp ne (ptr @__sanitizer_metadata_covered_add, ptr null), label %callfunc, label %ret
20592059
; CHECK-DAG: callfunc:
2060-
; CHECK-NEXT: call void @__sanitizer_metadata_covered_add(i32 1, ptr @__start_sanmd_covered, ptr @__stop_sanmd_covered)
2060+
; CHECK-NEXT: call void @__sanitizer_metadata_covered_add(i32 2, ptr @__start_sanmd_covered, ptr @__stop_sanmd_covered)
20612061
; CHECK-NEXT: br label %ret
20622062
; CHECK-DAG: ret:
20632063
; CHECK-NEXT: ret void
@@ -2066,11 +2066,11 @@ entry:
20662066
; CHECK-DAG: entry:
20672067
; CHECK-NEXT: br i1 icmp ne (ptr @__sanitizer_metadata_covered_del, ptr null), label %callfunc, label %ret
20682068
; CHECK-DAG: callfunc:
2069-
; CHECK-NEXT: call void @__sanitizer_metadata_covered_del(i32 1, ptr @__start_sanmd_covered, ptr @__stop_sanmd_covered)
2069+
; CHECK-NEXT: call void @__sanitizer_metadata_covered_del(i32 2, ptr @__start_sanmd_covered, ptr @__stop_sanmd_covered)
20702070
; CHECK-NEXT: br label %ret
20712071
; CHECK-DAG: ret:
20722072
; CHECK-NEXT: ret void
20732073

20742074
; CHECK: !0 = !{!"sanmd_covered", !1}
2075-
; CHECK: !1 = !{i32 1}
2075+
; CHECK: !1 = !{i8 1}
20762076
; CHECK: !2 = !{!"sanmd_atomics"}

0 commit comments

Comments
 (0)