[clang] 71c7313 - Add CFI integer types normalization

Sami Tolvanen via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 8 14:24:53 PST 2023


Author: Ramon de C Valle
Date: 2023-02-08T22:24:19Z
New Revision: 71c7313f42d2b6063fea09854cf4fc46fd0627e1

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

LOG: Add CFI integer types normalization

This commit adds a new option (i.e.,
`-fsanitize-cfi-icall-normalize-integers`) for normalizing integer types
as vendor extended types for cross-language LLVM CFI/KCFI support with
other languages that can't represent and encode C/C++ integer types.

Specifically, integer types are encoded as their defined representations
(e.g., 8-bit signed integer, 16-bit signed integer, 32-bit signed
integer, ...) for compatibility with languages that define
explicitly-sized integer types (e.g., i8, i16, i32, ..., in Rust).

``-fsanitize-cfi-icall-normalize-integers`` is compatible with
``-fsanitize-cfi-icall-generalize-pointers``.

This helps with providing cross-language CFI support with the Rust
compiler and is an alternative solution for the issue described and
alternatives proposed in the RFC
https://github.com/rust-lang/rfcs/pull/3296.

For more information about LLVM CFI/KCFI and cross-language LLVM
CFI/KCFI support for the Rust compiler, see the design document in the
tracking issue https://github.com/rust-lang/rust/issues/89653.

Relands b1e9ab7438a098a18fecda88fc87ef4ccadfcf1e with fixes.

Reviewed By: pcc, samitolvanen

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

Added: 
    clang/test/CodeGen/cfi-icall-normalize.c
    clang/test/CodeGen/cfi-icall-normalize2.c
    clang/test/CodeGen/kcfi-normalize.c

Modified: 
    clang/docs/ControlFlowIntegrity.rst
    clang/docs/UsersManual.rst
    clang/include/clang/AST/Mangle.h
    clang/include/clang/Basic/CodeGenOptions.def
    clang/include/clang/Driver/Options.td
    clang/include/clang/Driver/SanitizerArgs.h
    clang/lib/AST/ItaniumMangle.cpp
    clang/lib/AST/MicrosoftMangle.cpp
    clang/lib/CodeGen/CodeGenModule.cpp
    clang/lib/Driver/SanitizerArgs.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ControlFlowIntegrity.rst b/clang/docs/ControlFlowIntegrity.rst
index ef47b1c5b4b2b..f375199f40617 100644
--- a/clang/docs/ControlFlowIntegrity.rst
+++ b/clang/docs/ControlFlowIntegrity.rst
@@ -236,6 +236,25 @@ long as the qualifiers for the type they point to match. For example, ``char*``,
 ``-fsanitize-cfi-icall-generalize-pointers`` is not compatible with
 ``-fsanitize-cfi-cross-dso``.
 
+.. _cfi-icall-experimental-normalize-integers:
+
+``-fsanitize-cfi-icall-experimental-normalize-integers``
+--------------------------------------------------------
+
+This option enables normalizing integer types as vendor extended types for
+cross-language LLVM CFI/KCFI support with other languages that can't represent
+and encode C/C++ integer types.
+
+Specifically, integer types are encoded as their defined representations (e.g.,
+8-bit signed integer, 16-bit signed integer, 32-bit signed integer, ...) for
+compatibility with languages that define explicitly-sized integer types (e.g.,
+i8, i16, i32, ..., in Rust).
+
+``-fsanitize-cfi-icall-experimental-normalize-integers`` is compatible with
+``-fsanitize-cfi-icall-generalize-pointers``.
+
+This option is currently experimental.
+
 .. _cfi-canonical-jump-tables:
 
 ``-fsanitize-cfi-canonical-jump-tables``

diff  --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 18e1e9aaca2c4..0d5e960050c25 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -1992,6 +1992,14 @@ are listed below.
    checked by Control Flow Integrity indirect call checking. See
    :doc:`ControlFlowIntegrity` for more details.
 
+.. option:: -fsanitize-cfi-icall-experimental-normalize-integers
+
+   Normalize integers in return and argument types in function type signatures
+   checked by Control Flow Integrity indirect call checking. See
+   :doc:`ControlFlowIntegrity` for more details.
+
+   This option is currently experimental.
+
 .. option:: -fstrict-vtable-pointers
 
    Enable optimizations based on the strict rules for overwriting polymorphic

diff  --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h
index 9662a33c61cb7..c04bcc7f01cb4 100644
--- a/clang/include/clang/AST/Mangle.h
+++ b/clang/include/clang/AST/Mangle.h
@@ -140,7 +140,8 @@ class MangleContext {
                                         unsigned ManglingNumber,
                                         raw_ostream &) = 0;
   virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
-  virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0;
+  virtual void mangleCXXRTTIName(QualType T, raw_ostream &,
+                                 bool NormalizeIntegers = false) = 0;
   virtual void mangleStringLiteral(const StringLiteral *SL, raw_ostream &) = 0;
   virtual void mangleMSGuidDecl(const MSGuidDecl *GD, raw_ostream&);
 
@@ -177,7 +178,8 @@ class MangleContext {
   /// or type uniquing.
   /// TODO: Extend this to internal types by generating names that are unique
   /// across translation units so it can be used with LTO.
-  virtual void mangleTypeName(QualType T, raw_ostream &) = 0;
+  virtual void mangleTypeName(QualType T, raw_ostream &,
+                              bool NormalizeIntegers = false) = 0;
 
   /// @}
 };

diff  --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 436226c6f178f..6383ebea40a5a 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -257,6 +257,8 @@ CODEGENOPT(SanitizeMinimalRuntime, 1, 0) ///< Use "_minimal" sanitizer runtime f
                                          ///< diagnostics.
 CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0) ///< Generalize pointer types in
                                                      ///< CFI icall function signatures
+CODEGENOPT(SanitizeCfiICallNormalizeIntegers, 1, 0) ///< Normalize integer types in
+                                                    ///< CFI icall function signatures
 CODEGENOPT(SanitizeCfiCanonicalJumpTables, 1, 0) ///< Make jump table symbols canonical
                                                  ///< instead of creating a local jump table.
 CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage

diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 6392597153e34..6e7cdf131d937 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1900,6 +1900,10 @@ def fsanitize_cfi_icall_generalize_pointers : Flag<["-"], "fsanitize-cfi-icall-g
                                               Group<f_clang_Group>,
                                               HelpText<"Generalize pointers in CFI indirect call type signature checks">,
                                               MarshallingInfoFlag<CodeGenOpts<"SanitizeCfiICallGeneralizePointers">>;
+def fsanitize_cfi_icall_normalize_integers : Flag<["-"], "fsanitize-cfi-icall-experimental-normalize-integers">,
+                                             Group<f_clang_Group>,
+                                             HelpText<"Normalize integers in CFI indirect call type signature checks">,
+                                             MarshallingInfoFlag<CodeGenOpts<"SanitizeCfiICallNormalizeIntegers">>;
 defm sanitize_cfi_canonical_jump_tables : BoolOption<"f", "sanitize-cfi-canonical-jump-tables",
   CodeGenOpts<"SanitizeCfiCanonicalJumpTables">, DefaultFalse,
   PosFlag<SetTrue, [], "Make">, NegFlag<SetFalse, [CoreOption, NoXarchOption], "Do not make">,

diff  --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h
index 52889c3fe1895..abc5271b0a811 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -37,6 +37,7 @@ class SanitizerArgs {
   bool MsanParamRetval = true;
   bool CfiCrossDso = false;
   bool CfiICallGeneralizePointers = false;
+  bool CfiICallNormalizeIntegers = false;
   bool CfiCanonicalJumpTables = false;
   int AsanFieldPadding = 0;
   bool SharedRuntime = false;

diff  --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 88549c7344506..ed8bac6947a4a 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -109,8 +109,10 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
   void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
                            const CXXRecordDecl *Type, raw_ostream &) override;
   void mangleCXXRTTI(QualType T, raw_ostream &) override;
-  void mangleCXXRTTIName(QualType T, raw_ostream &) override;
-  void mangleTypeName(QualType T, raw_ostream &) override;
+  void mangleCXXRTTIName(QualType T, raw_ostream &,
+                         bool NormalizeIntegers) override;
+  void mangleTypeName(QualType T, raw_ostream &,
+                      bool NormalizeIntegers) override;
 
   void mangleCXXCtorComdat(const CXXConstructorDecl *D, raw_ostream &) override;
   void mangleCXXDtorComdat(const CXXDestructorDecl *D, raw_ostream &) override;
@@ -215,6 +217,10 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
 class CXXNameMangler {
   ItaniumMangleContextImpl &Context;
   raw_ostream &Out;
+  /// Normalize integer types for cross-language CFI support with other
+  /// languages that can't represent and encode C/C++ integer types.
+  bool NormalizeIntegers = false;
+
   bool NullOut = false;
   /// In the "DisableDerivedAbiTags" mode derived ABI tags are not calculated.
   /// This mode is used when mangler creates another mangler recursively to
@@ -413,6 +419,10 @@ class CXXNameMangler {
       : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
         AbiTagsRoot(AbiTags) {}
 
+  CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_,
+                 bool NormalizeIntegers_)
+      : Context(C), Out(Out_), NormalizeIntegers(NormalizeIntegers_),
+        NullOut(false), Structor(nullptr), AbiTagsRoot(AbiTags) {}
   CXXNameMangler(CXXNameMangler &Outer, raw_ostream &Out_)
       : Context(Outer.Context), Out(Out_), Structor(Outer.Structor),
         StructorType(Outer.StructorType), SeqID(Outer.SeqID),
@@ -2937,6 +2947,85 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
   //                 ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
   //                 ::= u <source-name>    # vendor extended type
   std::string type_name;
+  // Normalize integer types as vendor extended types:
+  // u<length>i<type size>
+  // u<length>u<type size>
+  if (NormalizeIntegers && T->isInteger()) {
+    if (T->isSignedInteger()) {
+      switch (getASTContext().getTypeSize(T)) {
+      case 8:
+        // Pick a representative for each integer size in the substitution
+        // dictionary. (Its actual defined size is not relevant.)
+        if (mangleSubstitution(BuiltinType::SChar))
+          break;
+        Out << "u2i8";
+        addSubstitution(BuiltinType::SChar);
+        break;
+      case 16:
+        if (mangleSubstitution(BuiltinType::Short))
+          break;
+        Out << "u3i16";
+        addSubstitution(BuiltinType::Short);
+        break;
+      case 32:
+        if (mangleSubstitution(BuiltinType::Int))
+          break;
+        Out << "u3i32";
+        addSubstitution(BuiltinType::Int);
+        break;
+      case 64:
+        if (mangleSubstitution(BuiltinType::Long))
+          break;
+        Out << "u3i64";
+        addSubstitution(BuiltinType::Long);
+        break;
+      case 128:
+        if (mangleSubstitution(BuiltinType::Int128))
+          break;
+        Out << "u4i128";
+        addSubstitution(BuiltinType::Int128);
+        break;
+      default:
+        llvm_unreachable("Unknown integer size for normalization");
+      }
+    } else {
+      switch (getASTContext().getTypeSize(T)) {
+      case 8:
+        if (mangleSubstitution(BuiltinType::UChar))
+          break;
+        Out << "u2u8";
+        addSubstitution(BuiltinType::UChar);
+        break;
+      case 16:
+        if (mangleSubstitution(BuiltinType::UShort))
+          break;
+        Out << "u3u16";
+        addSubstitution(BuiltinType::UShort);
+        break;
+      case 32:
+        if (mangleSubstitution(BuiltinType::UInt))
+          break;
+        Out << "u3u32";
+        addSubstitution(BuiltinType::UInt);
+        break;
+      case 64:
+        if (mangleSubstitution(BuiltinType::ULong))
+          break;
+        Out << "u3u64";
+        addSubstitution(BuiltinType::ULong);
+        break;
+      case 128:
+        if (mangleSubstitution(BuiltinType::UInt128))
+          break;
+        Out << "u4u128";
+        addSubstitution(BuiltinType::UInt128);
+        break;
+      default:
+        llvm_unreachable("Unknown integer size for normalization");
+      }
+    }
+    return;
+  }
   switch (T->getKind()) {
   case BuiltinType::Void:
     Out << 'v';
@@ -6523,16 +6612,17 @@ void ItaniumMangleContextImpl::mangleCXXRTTI(QualType Ty, raw_ostream &Out) {
   Mangler.mangleType(Ty);
 }
 
-void ItaniumMangleContextImpl::mangleCXXRTTIName(QualType Ty,
-                                                 raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXRTTIName(
+    QualType Ty, raw_ostream &Out, bool NormalizeIntegers = false) {
   // <special-name> ::= TS <type>  # typeinfo name (null terminated byte string)
-  CXXNameMangler Mangler(*this, Out);
+  CXXNameMangler Mangler(*this, Out, NormalizeIntegers);
   Mangler.getStream() << "_ZTS";
   Mangler.mangleType(Ty);
 }
 
-void ItaniumMangleContextImpl::mangleTypeName(QualType Ty, raw_ostream &Out) {
-  mangleCXXRTTIName(Ty, Out);
+void ItaniumMangleContextImpl::mangleTypeName(QualType Ty, raw_ostream &Out,
+                                              bool NormalizeIntegers = false) {
+  mangleCXXRTTIName(Ty, Out, NormalizeIntegers);
 }
 
 void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, raw_ostream &) {

diff  --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index cdd2c93c4b147..09fda417faeb5 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -180,7 +180,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
                               int32_t VBPtrOffset, uint32_t VBIndex,
                               raw_ostream &Out) override;
   void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
-  void mangleCXXRTTIName(QualType T, raw_ostream &Out) override;
+  void mangleCXXRTTIName(QualType T, raw_ostream &Out,
+                         bool NormalizeIntegers) override;
   void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived,
                                         uint32_t NVOffset, int32_t VBPtrOffset,
                                         uint32_t VBTableOffset, uint32_t Flags,
@@ -193,7 +194,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
   mangleCXXRTTICompleteObjectLocator(const CXXRecordDecl *Derived,
                                      ArrayRef<const CXXRecordDecl *> BasePath,
                                      raw_ostream &Out) override;
-  void mangleTypeName(QualType T, raw_ostream &) override;
+  void mangleTypeName(QualType T, raw_ostream &,
+                      bool NormalizeIntegers) override;
   void mangleReferenceTemporary(const VarDecl *, unsigned ManglingNumber,
                                 raw_ostream &) override;
   void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out) override;
@@ -3586,8 +3588,8 @@ void MicrosoftMangleContextImpl::mangleCXXRTTI(QualType T, raw_ostream &Out) {
   Mangler.getStream() << "@8";
 }
 
-void MicrosoftMangleContextImpl::mangleCXXRTTIName(QualType T,
-                                                   raw_ostream &Out) {
+void MicrosoftMangleContextImpl::mangleCXXRTTIName(
+    QualType T, raw_ostream &Out, bool NormalizeIntegers = false) {
   MicrosoftCXXNameMangler Mangler(*this, Out);
   Mangler.getStream() << '.';
   Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
@@ -3754,7 +3756,8 @@ void MicrosoftMangleContextImpl::mangleSEHFinallyBlock(
   Mangler.mangleName(EnclosingDecl);
 }
 
-void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
+void MicrosoftMangleContextImpl::mangleTypeName(
+    QualType T, raw_ostream &Out, bool NormalizeIntegers = false) {
   // This is just a made up unique string for the purposes of tbaa.  undname
   // does *not* know how to demangle it.
   MicrosoftCXXNameMangler Mangler(*this, Out);

diff  --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 0f93c33194353..71ec831435356 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1731,7 +1731,11 @@ llvm::ConstantInt *CodeGenModule::CreateKCFITypeId(QualType T) {
 
   std::string OutName;
   llvm::raw_string_ostream Out(OutName);
-  getCXXABI().getMangleContext().mangleTypeName(T, Out);
+  getCXXABI().getMangleContext().mangleTypeName(
+      T, Out, getCodeGenOpts().SanitizeCfiICallNormalizeIntegers);
+
+  if (getCodeGenOpts().SanitizeCfiICallNormalizeIntegers)
+    Out << ".normalized";
 
   return llvm::ConstantInt::get(Int32Ty,
                                 static_cast<uint32_t>(llvm::xxHash64(OutName)));
@@ -6949,7 +6953,12 @@ CodeGenModule::CreateMetadataIdentifierImpl(QualType T, MetadataTypeMap &Map,
   if (isExternallyVisible(T->getLinkage())) {
     std::string OutName;
     llvm::raw_string_ostream Out(OutName);
-    getCXXABI().getMangleContext().mangleTypeName(T, Out);
+    getCXXABI().getMangleContext().mangleTypeName(
+        T, Out, getCodeGenOpts().SanitizeCfiICallNormalizeIntegers);
+
+    if (getCodeGenOpts().SanitizeCfiICallNormalizeIntegers)
+      Out << ".normalized";
+
     Out << Suffix;
 
     InternalId = llvm::MDString::get(getLLVMContext(), Out.str());

diff  --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 4f74093d7d247..800d1e63e56cc 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -713,6 +713,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
     CfiICallGeneralizePointers =
         Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers);
 
+    CfiICallNormalizeIntegers =
+        Args.hasArg(options::OPT_fsanitize_cfi_icall_normalize_integers);
+
     if (CfiCrossDso && CfiICallGeneralizePointers && DiagnoseErrors)
       D.Diag(diag::err_drv_argument_not_allowed_with)
           << "-fsanitize-cfi-cross-dso"
@@ -1217,6 +1220,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
   if (CfiICallGeneralizePointers)
     CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers");
 
+  if (CfiICallNormalizeIntegers)
+    CmdArgs.push_back("-fsanitize-cfi-icall-experimental-normalize-integers");
+
   if (CfiCanonicalJumpTables)
     CmdArgs.push_back("-fsanitize-cfi-canonical-jump-tables");
 

diff  --git a/clang/test/CodeGen/cfi-icall-normalize.c b/clang/test/CodeGen/cfi-icall-normalize.c
new file mode 100644
index 0000000000000..3a55ad1b4a8b3
--- /dev/null
+++ b/clang/test/CodeGen/cfi-icall-normalize.c
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -fsanitize-cfi-icall-experimental-normalize-integers -emit-llvm -o - %s | FileCheck %s
+
+// Test that integer types are normalized for cross-language CFI support with
+// other languages that can't represent and encode C/C++ integer types.
+
+void foo0(char arg) { }
+// CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}}
+void foo1(char arg1, signed char arg2) { }
+// CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}}
+void foo2(char arg1, signed char arg2, signed char arg3) { }
+// CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}}
+void foo3(int arg) { }
+// CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}}
+void foo4(int arg1, int arg2) { }
+// CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}}
+void foo5(int arg1, int arg2, int arg3) { }
+// CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}}
+void foo6(long arg) { }
+// CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}}
+void foo7(long arg1, long long arg2) { }
+// CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}}
+void foo8(long arg1, long long arg2, long long arg3) { }
+// CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}}
+void foo9(short arg) { }
+// CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}}
+void foo10(short arg1, short arg2) { }
+// CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}}
+void foo11(short arg1, short arg2, short arg3) { }
+// CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}}
+void foo12(unsigned char arg) { }
+// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}}
+void foo13(unsigned char arg1, unsigned char arg2) { }
+// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}}
+void foo14(unsigned char arg1, unsigned char arg2, unsigned char arg3) { }
+// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}}
+void foo15(unsigned int arg) { }
+// CHECK: define{{.*}}foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}}
+void foo16(unsigned int arg1, unsigned int arg2) { }
+// CHECK: define{{.*}}foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}}
+void foo17(unsigned int arg1, unsigned int arg2, unsigned int arg3) { }
+// CHECK: define{{.*}}foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}}
+void foo18(unsigned long arg) { }
+// CHECK: define{{.*}}foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}}
+void foo19(unsigned long arg1, unsigned long long arg2) { }
+// CHECK: define{{.*}}foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}}
+void foo20(unsigned long arg1, unsigned long long arg2, unsigned long long arg3) { }
+// CHECK: define{{.*}}foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}}
+void foo21(unsigned short arg) { }
+// CHECK: define{{.*}}foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}}
+void foo22(unsigned short arg1, unsigned short arg2) { }
+// CHECK: define{{.*}}foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}}
+void foo23(unsigned short arg1, unsigned short arg2, unsigned short arg3) { }
+// CHECK: define{{.*}}foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}}
+
+// CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvu2i8E.normalized"}
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu2i8S_E.normalized"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu2i8S_S_E.normalized"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3i32E.normalized"}
+// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3i32S_E.normalized"}
+// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3i32S_S_E.normalized"}
+// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3i64E.normalized"}
+// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3i64S_E.normalized"}
+// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3i64S_S_E.normalized"}
+// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3i16E.normalized"}
+// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3i16S_E.normalized"}
+// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3i16S_S_E.normalized"}
+// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu2u8E.normalized"}
+// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu2u8S_E.normalized"}
+// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu2u8S_S_E.normalized"}
+// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3u32E.normalized"}
+// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3u32S_E.normalized"}
+// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3u32S_S_E.normalized"}
+// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3u64E.normalized"}
+// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3u64S_E.normalized"}
+// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3u64S_S_E.normalized"}
+// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3u16E.normalized"}
+// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3u16S_E.normalized"}
+// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3u16S_S_E.normalized"}

diff  --git a/clang/test/CodeGen/cfi-icall-normalize2.c b/clang/test/CodeGen/cfi-icall-normalize2.c
new file mode 100644
index 0000000000000..93893065cf903
--- /dev/null
+++ b/clang/test/CodeGen/cfi-icall-normalize2.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -fsanitize-cfi-icall-experimental-normalize-integers -emit-llvm -o - %s | FileCheck %s
+
+// Test that normalized type metadata for functions are emitted for cross-language CFI support with
+// other languages that can't represent and encode C/C++ integer types.
+
+void foo(void (*fn)(int), int arg) {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME: {{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}}
+    // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFvu3i32E.normalized")
+    fn(arg);
+}
+
+void bar(void (*fn)(int, int), int arg1, int arg2) {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME: {{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}}
+    // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFvu3i32S_E.normalized")
+    fn(arg1, arg2);
+}
+
+void baz(void (*fn)(int, int, int), int arg1, int arg2, int arg3) {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME: {{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}}
+    // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0}}, metadata !"_ZTSFvu3i32S_S_E.normalized")
+    fn(arg1, arg2, arg3);
+}
+
+// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPFvu3i32ES_E.normalized"}
+// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvPFvu3i32S_ES_S_E.normalized"}
+// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPFvu3i32S_S_ES_S_S_E.normalized"}

diff  --git a/clang/test/CodeGen/kcfi-normalize.c b/clang/test/CodeGen/kcfi-normalize.c
new file mode 100644
index 0000000000000..7660c908a7bdd
--- /dev/null
+++ b/clang/test/CodeGen/kcfi-normalize.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fsanitize-cfi-icall-experimental-normalize-integers -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fsanitize=kcfi -fsanitize-cfi-icall-experimental-normalize-integers -x c++ -o - %s | FileCheck %s
+#if !__has_feature(kcfi)
+#error Missing kcfi?
+#endif
+
+// Test that normalized type metadata for functions are emitted for cross-language KCFI support with
+// other languages that can't represent and encode C/C++ integer types.
+
+void foo(void (*fn)(int), int arg) {
+    // CHECK-LABEL: define{{.*}}foo
+    // CHECK-SAME: {{.*}}!kcfi_type ![[TYPE1:[0-9]+]]
+    // CHECK: call void %0(i32 noundef %1){{.*}}[ "kcfi"(i32 1162514891) ]
+    fn(arg);
+}
+
+void bar(void (*fn)(int, int), int arg1, int arg2) {
+    // CHECK-LABEL: define{{.*}}bar
+    // CHECK-SAME: {{.*}}!kcfi_type ![[TYPE2:[0-9]+]]
+    // CHECK: call void %0(i32 noundef %1, i32 noundef %2){{.*}}[ "kcfi"(i32 448046469) ]
+    fn(arg1, arg2);
+}
+
+void baz(void (*fn)(int, int, int), int arg1, int arg2, int arg3) {
+    // CHECK-LABEL: define{{.*}}baz
+    // CHECK-SAME: {{.*}}!kcfi_type ![[TYPE3:[0-9]+]]
+    // CHECK: call void %0(i32 noundef %1, i32 noundef %2, i32 noundef %3){{.*}}[ "kcfi"(i32 -2049681433) ]
+    fn(arg1, arg2, arg3);
+}
+
+// CHECK: ![[TYPE1]] = !{i32 -1143117868}
+// CHECK: ![[TYPE2]] = !{i32 -460921415}
+// CHECK: ![[TYPE3]] = !{i32 -333839615}


        


More information about the cfe-commits mailing list