[llvm] 78a784b - [asan] Emit .size directive for global object size before redzone

Alex Brachet via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 21 13:46:59 PDT 2022


Author: Alex Brachet
Date: 2022-04-21T20:46:38Z
New Revision: 78a784bea443cdcecf894155ab37893d7a8e8332

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

LOG: [asan] Emit .size directive for global object size before redzone

This emits an `st_size` that represents the actual useable size of an object before the redzone is added.

Reviewed By: vitalybuka, MaskRay, hctim

Differential Revision: https://reviews.llvm.org/D123010

Added: 
    llvm/test/CodeGen/X86/explicit-size-metadata.ll
    llvm/test/Verifier/explicit_size.ll

Modified: 
    llvm/docs/LangRef.rst
    llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
    llvm/lib/IR/Verifier.cpp
    llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
    llvm/test/Instrumentation/AddressSanitizer/adaptive_global_redzones.ll
    llvm/test/Instrumentation/AddressSanitizer/debug-info-global-var.ll

Removed: 
    


################################################################################
diff  --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 98e90a65073ad..104a8d4e271ed 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -7094,6 +7094,16 @@ Example:
     %a.addr = alloca float*, align 8, !annotation !0
     !0 = !{!"auto-init"}
 
+'``explicit_size``' Metadata
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``explicit_size`` metadata may be attached to a global variable definition
+with a size 
diff erent from the object's total size. This can be useful when an
+instrumentation enlarges the object while the symbol size should reflect the
+accessible or meaningful part of the object. This is currently only meaningful
+on ELF where an objects ``st_size`` can be controlled with a ``.size``
+directive. This metadata is ignored in contexts where it cannot be honored.
+
 Module Flags Metadata
 =====================
 

diff  --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index ea8a86b2e3757..13b88b7bbeba7 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -858,10 +858,17 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
 
   emitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer());
 
-  if (MAI->hasDotTypeDotSizeDirective())
+  if (MAI->hasDotTypeDotSizeDirective()) {
+    if (const MDNode *ExplicitValue = GV->getMetadata("explicit_size")) {
+      const auto *MetadataValue =
+          cast<ValueAsMetadata>(ExplicitValue->getOperand(0));
+      const auto *CI = cast<ConstantInt>(MetadataValue->getValue());
+      Size = CI->getZExtValue();
+    }
     // .size foo, 42
     OutStreamer->emitELFSize(EmittedInitSym,
                              MCConstantExpr::create(Size, OutContext));
+  }
 
   OutStreamer->AddBlankLine();
 }

diff  --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 09d47954c05e7..6f7f76f8e4679 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -776,6 +776,20 @@ void Verifier::visitGlobalVariable(const GlobalVariable &GV) {
                      "DIGlobalVariableExpression");
   }
 
+  MDs.clear();
+  GV.getMetadata("explicit_size", MDs);
+  if (MDs.size()) {
+    Check(MDs.size() == 1,
+          "only one !explicit_size can be attached to a global variable");
+    Check(MDs[0]->getNumOperands() == 1,
+          "!explicit_size must have exactly one operand");
+    const auto *MetadataValue =
+        dyn_cast<ValueAsMetadata>(MDs[0]->getOperand(0));
+    Check(MetadataValue, "!explicit_size operand must be a value");
+    const auto *CI = dyn_cast<ConstantInt>(MetadataValue->getValue());
+    Check(CI, "!explicit_size value must be an integer");
+  }
+
   // Scalable vectors cannot be global variables, since we don't know
   // the runtime size. If the global is an array containing scalable vectors,
   // that will be caught by the isValidElementType methods in StructType or

diff  --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
index 7dfe98c1a92a0..c8cae1b456b5d 100644
--- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -2511,6 +2511,12 @@ bool ModuleAddressSanitizer::InstrumentGlobals(IRBuilder<> &IRB, Module &M,
     // zero so we can copy the metadata over as is.
     NewGlobal->copyMetadata(G, 0);
 
+    LLVMContext &C = NewGlobal->getContext();
+    MDBuilder MDB{C};
+    MDTuple *MDN = MDNode::get(C, MDB.createConstant(ConstantInt::get(
+                                      Type::getInt64Ty(C), SizeInBytes)));
+    NewGlobal->setMetadata("explicit_size", MDN);
+
     Value *Indices2[2];
     Indices2[0] = IRB.getInt32(0);
     Indices2[1] = IRB.getInt32(0);

diff  --git a/llvm/test/CodeGen/X86/explicit-size-metadata.ll b/llvm/test/CodeGen/X86/explicit-size-metadata.ll
new file mode 100644
index 0000000000000..985073f91e21d
--- /dev/null
+++ b/llvm/test/CodeGen/X86/explicit-size-metadata.ll
@@ -0,0 +1,15 @@
+; RUN: llc < %s -mtriple=x86_64 | FileCheck %s
+
+ at a = global i64 0, align 8, !explicit_size !0
+; CHECK: .size a, 4
+
+ at b = global i64 0, align 8
+; CHECK: .size b, 8
+
+ at larger = global i16 0, align 4, !explicit_size !0
+; CHECK: .size larger, 4
+
+ at array = global { [8 x i8] } zeroinitializer, !explicit_size !0
+; CHECK: .size array, 4
+
+!0 = !{i64 4}

diff  --git a/llvm/test/Instrumentation/AddressSanitizer/adaptive_global_redzones.ll b/llvm/test/Instrumentation/AddressSanitizer/adaptive_global_redzones.ll
index 1aa1ac25ea8a6..e3edf5fd18504 100644
--- a/llvm/test/Instrumentation/AddressSanitizer/adaptive_global_redzones.ll
+++ b/llvm/test/Instrumentation/AddressSanitizer/adaptive_global_redzones.ll
@@ -6,14 +6,14 @@ target triple = "x86_64-unknown-linux-gnu"
 ; Here we check that the global redzone sizes grow with the object size.
 
 @G10 = global [10 x i8] zeroinitializer, align 1
-; CHECK: @G10 = global { [10 x i8], [22 x i8] }
+; CHECK: @G10 = global { [10 x i8], [22 x i8] } zeroinitializer, align 32, !explicit_size ![[#TAG10:]]
 
 @G31 = global [31 x i8] zeroinitializer, align 1
 @G32 = global [32 x i8] zeroinitializer, align 1
 @G33 = global [33 x i8] zeroinitializer, align 1
-; CHECK: @G31 = global { [31 x i8], [33 x i8] }
-; CHECK: @G32 = global { [32 x i8], [32 x i8] }
-; CHECK: @G33 = global { [33 x i8], [63 x i8] }
+; CHECK: @G31 = global { [31 x i8], [33 x i8] } zeroinitializer, align 32, !explicit_size ![[#TAG31:]]
+; CHECK: @G32 = global { [32 x i8], [32 x i8] } zeroinitializer, align 32, !explicit_size ![[#TAG32:]]
+; CHECK: @G33 = global { [33 x i8], [63 x i8] } zeroinitializer, align 32, !explicit_size ![[#TAG33:]]
 
 @G63 = global [63 x i8] zeroinitializer, align 1
 @G64 = global [64 x i8] zeroinitializer, align 1
@@ -53,6 +53,12 @@ target triple = "x86_64-unknown-linux-gnu"
 @G1000000 = global [1000000 x i8] zeroinitializer, align 1
 @G10000000 = global [10000000 x i8] zeroinitializer, align 1
 @G100000000 = global [100000000 x i8] zeroinitializer, align 1
-; CHECK: @G1000000 = global { [1000000 x i8], [249984 x i8] }
-; CHECK: @G10000000 = global { [10000000 x i8], [262144 x i8] }
-; CHECK: @G100000000 = global { [100000000 x i8], [262144 x i8] }
+; CHECK: @G1000000 = global { [1000000 x i8], [249984 x i8] } zeroinitializer, align 32, !explicit_size ![[#]]
+; CHECK: @G10000000 = global { [10000000 x i8], [262144 x i8] } zeroinitializer, align 32, !explicit_size ![[#]]
+; CHECK: @G100000000 = global { [100000000 x i8], [262144 x i8] } zeroinitializer, align 32, !explicit_size ![[#TAGBIG:]]
+
+; CHECK: ![[#TAG10]] = !{i64 10}
+; CHECK: ![[#TAG31]] = !{i64 31}
+; CHECK: ![[#TAG32]] = !{i64 32}
+; CHECK: ![[#TAG33]] = !{i64 33}
+; CHECK: ![[#TAGBIG]] = !{i64 100000000}

diff  --git a/llvm/test/Instrumentation/AddressSanitizer/debug-info-global-var.ll b/llvm/test/Instrumentation/AddressSanitizer/debug-info-global-var.ll
index 783a7385721dc..b4c867686c71e 100644
--- a/llvm/test/Instrumentation/AddressSanitizer/debug-info-global-var.ll
+++ b/llvm/test/Instrumentation/AddressSanitizer/debug-info-global-var.ll
@@ -2,7 +2,7 @@
 source_filename = "version.c"
 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-apple-macosx10.12.0"
-; CHECK: @version = constant { [5 x i8], [27 x i8] } {{.*}}, !dbg ![[GV:.*]]
+; CHECK: @version = constant { [5 x i8], [27 x i8] } {{.*}}, !dbg ![[GV:.*]],
 
 @version = constant [5 x i8] c"4.00\00", align 1, !dbg !0
 

diff  --git a/llvm/test/Verifier/explicit_size.ll b/llvm/test/Verifier/explicit_size.ll
new file mode 100644
index 0000000000000..e91a04383611b
--- /dev/null
+++ b/llvm/test/Verifier/explicit_size.ll
@@ -0,0 +1,31 @@
+; RUN: split-file %s %t
+; RUN: not opt -verify -disable-output < %t/multiple.ll 2>&1 | FileCheck %s --check-prefix=MULTIPLE
+; RUN: not opt -verify -disable-output < %t/operands.ll 2>&1 | FileCheck %s --check-prefix=OPERANDS
+; RUN: not opt -verify -disable-output < %t/invalid_md.ll 2>&1 | FileCheck %s --check-prefix=INVALID_MD
+; RUN: not opt -verify -disable-output < %t/not_int.ll 2>&1 | FileCheck %s --check-prefix=NOT_INT
+
+; MULTIPLE: only one !explicit_size can be attached to a global variable
+;--- multiple.ll
+ at a = global { i32, [28 x i8] } zeroinitializer, align 32, !explicit_size !0, !explicit_size !0
+
+!0 = !{i64 4}
+
+; OPERANDS: !explicit_size must have exactly one operand
+;--- operands.ll
+ at a = global { i32, [28 x i8] } zeroinitializer, align 32, !explicit_size !0
+
+!0 = !{i64 4, i64 4}
+
+; INVALID_MD: !explicit_size operand must be a value
+;--- invalid_md.ll
+ at a = global { i32, [28 x i8] } zeroinitializer, align 32, !explicit_size !0
+
+!0 = !{!1}
+!1 = !{i64 4}
+
+; NOT_INT: !explicit_size value must be an integer
+;--- not_int.ll
+ at a = global { i32, [28 x i8] } zeroinitializer, align 32, !explicit_size !0
+declare i32 @b()
+
+!0 = !{i32 ()* @b}


        


More information about the llvm-commits mailing list