Browse Source

WINDOWS_EXPORT_ALL_SYMBOLS: Do not export C++ operators declared extern "C"

The pattern `extern "C" { inline bool operator==(...) {} }` appears
in at least one Windows SDK header, `winnt.h`.  Translation units that
instantiate the inline symbol produce object files with a symbol named
just `==`.  Avoid exporting such symbols because the linker will not
recognize them.

Fixes: #24999
Tolga Mizrak 7 months ago
parent
commit
607d9cf561
2 changed files with 40 additions and 2 deletions
  1. 10 2
      Source/bindexplib.cxx
  2. 30 0
      Tests/RunCMake/AutoExportDll/hello.cxx

+ 10 - 2
Source/bindexplib.cxx

@@ -290,9 +290,11 @@ public:
               symbol.compare(0, 4, vectorPrefix)) {
             SectChar = this->SectionHeaders[pSymbolTable->SectionNumber - 1]
                          .Characteristics;
-            // skip symbols containing a dot or are from managed code
+            // Skip symbols containing a dot, are from managed code,
+            // or are C++ operators incorrectly declared extern "C".
             if (symbol.find('.') == std::string::npos &&
-                !SymbolIsFromManagedCode(symbol)) {
+                !SymbolIsFromManagedCode(symbol) &&
+                !SymbolIsOperatorExternC(symbol)) {
               // skip arm64ec thunk symbols
               if (this->SymbolArch != Arch::ARM64EC ||
                   (symbol.find("$ientry_thunk") == std::string::npos &&
@@ -337,6 +339,12 @@ private:
       symbol.find("$$J") != std::string::npos;
   }
 
+  bool SymbolIsOperatorExternC(std::string const& symbol)
+  {
+    return symbol.find_first_not_of("=<>+-*/%,?|~!^&[]()") ==
+      std::string::npos;
+  }
+
   std::set<std::string>& Symbols;
   std::set<std::string>& DataSymbols;
   DWORD_PTR SymbolCount;

+ 30 - 0
Tests/RunCMake/AutoExportDll/hello.cxx

@@ -21,3 +21,33 @@ HelloVFTable::~HelloVFTable()
 {
 }
 #endif
+
+#ifndef __SUNPRO_CC
+// C++ operators incorrectly declared extern "C" should *not* be exported.
+extern "C" {
+bool operator==(Hello const&, Hello const&)
+{
+  return false;
+}
+bool operator!=(Hello const&, Hello const&)
+{
+  return false;
+}
+bool operator<(Hello const&, Hello const&)
+{
+  return false;
+}
+bool operator<=(Hello const&, Hello const&)
+{
+  return false;
+}
+bool operator>(Hello const&, Hello const&)
+{
+  return false;
+}
+bool operator>=(Hello const&, Hello const&)
+{
+  return false;
+}
+}
+#endif