versioner: Add versioner_fortify_inline annotation

This commit adds versioner_fortify_inline annotation.  This annotation
indicates that the annotated function is an overloaded inline function
for _FORTIFY_SOURCE implementation.  They are usually enabled/disabled
by the enable_if attribute, thus the versioner don't have to check
whether they have conflicting definitions.

Bug: 118991081
Test: source development/vndk/tools/header-checker/android/envsetup.sh && \
      source build/envsetup.sh && \
      lunch aosp_arm64-userdebug && \
      m versioner && \
      ./bionic/tools/versioner/run_tests.py
Change-Id: If5c739fc0c8a218907855939c1fe5338134da7f7
diff --git a/tools/versioner/src/DeclarationDatabase.cpp b/tools/versioner/src/DeclarationDatabase.cpp
index 0ba51d1..afae509 100644
--- a/tools/versioner/src/DeclarationDatabase.cpp
+++ b/tools/versioner/src/DeclarationDatabase.cpp
@@ -106,6 +106,7 @@
     bool is_extern = named_decl->getFormalLinkage() == ExternalLinkage;
     bool is_definition = false;
     bool no_guard = false;
+    bool fortify_inline = false;
 
     if (auto function_decl = dyn_cast<FunctionDecl>(decl)) {
       is_definition = function_decl->isThisDeclarationADefinition();
@@ -147,6 +148,8 @@
       llvm::StringRef annotation = attr->getAnnotation();
       if (annotation == "versioner_no_guard") {
         no_guard = true;
+      } else if (annotation == "versioner_fortify_inline") {
+        fortify_inline = true;
       } else {
         llvm::SmallVector<llvm::StringRef, 2> fragments;
         annotation.split(fragments, "=");
@@ -217,7 +220,8 @@
         declaration_it != symbol_it->second.declarations.end()) {
       if (declaration_it->second.is_extern != is_extern ||
           declaration_it->second.is_definition != is_definition ||
-          declaration_it->second.no_guard != no_guard) {
+          declaration_it->second.no_guard != no_guard ||
+          declaration_it->second.fortify_inline != fortify_inline) {
         errx(1, "varying declaration of '%s' at %s:%u:%u", declaration_name.c_str(),
              location.filename.c_str(), location.start.line, location.start.column);
       }
@@ -229,6 +233,7 @@
       declaration.is_extern = is_extern;
       declaration.is_definition = is_definition;
       declaration.no_guard = no_guard;
+      declaration.fortify_inline = fortify_inline;
       declaration.availability.insert(std::make_pair(type, availability));
       symbol_it->second.declarations.insert(std::make_pair(location, declaration));
     }
diff --git a/tools/versioner/src/DeclarationDatabase.h b/tools/versioner/src/DeclarationDatabase.h
index 4496ee9..9a45227 100644
--- a/tools/versioner/src/DeclarationDatabase.h
+++ b/tools/versioner/src/DeclarationDatabase.h
@@ -127,6 +127,7 @@
   bool is_extern;
   bool is_definition;
   bool no_guard;
+  bool fortify_inline;
   std::map<CompilationType, DeclarationAvailability> availability;
 
   bool calculateAvailability(DeclarationAvailability* output) const;
@@ -143,6 +144,9 @@
     if (no_guard) {
       fprintf(out, "no_guard ");
     }
+    if (fortify_inline) {
+      fprintf(out, "fortify_inline ");
+    }
     fprintf(out, "@ %s:%u:%u", StripPrefix(location.filename, base_path).str().c_str(),
             location.start.line, location.start.column);
 
diff --git a/tools/versioner/src/versioner.cpp b/tools/versioner/src/versioner.cpp
index d3c2f7c..473f1f9 100644
--- a/tools/versioner/src/versioner.cpp
+++ b/tools/versioner/src/versioner.cpp
@@ -277,7 +277,9 @@
 }
 
 // Perform a sanity check on a symbol's declarations, enforcing the following invariants:
-//   1. At most one inline definition of the function exists.
+//   1. At most one inline definition of the function exists (overloaded inline functions for
+//      _FORTIFY_SOURCE do not count because they are usually introduced to intercept the original
+//      functions or usually have enable_if attributes).
 //   2. All of the availability declarations for a symbol are compatible.
 //      If a function is declared as an inline before a certain version, the inline definition
 //      should have no version tag.
@@ -290,7 +292,7 @@
   std::unordered_map<const Declaration*, std::set<CompilationType>> inline_definitions;
   for (const auto& decl_it : symbol.declarations) {
     const Declaration* decl = &decl_it.second;
-    if (decl->is_definition) {
+    if (decl->is_definition && !decl->fortify_inline) {
       std::set<CompilationType> compilation_types = getCompilationTypes(decl);
       for (const auto& inline_def_it : inline_definitions) {
         auto intersection = Intersection(compilation_types, inline_def_it.second);
diff --git a/tools/versioner/tests/fortify_inline/headers/fcntl.h b/tools/versioner/tests/fortify_inline/headers/fcntl.h
new file mode 100644
index 0000000..dc81ef8
--- /dev/null
+++ b/tools/versioner/tests/fortify_inline/headers/fcntl.h
@@ -0,0 +1,29 @@
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern int open_real(const char* name, int flags, ...) __asm__("open");
+
+#define O_CREAT 00000100
+
+typedef unsigned int mode_t;
+
+static inline __attribute__((always_inline))
+int open(const char* name, int flags)
+    __attribute__((annotate("versioner_fortify_inline")))
+    __attribute__((overloadable))
+    __attribute__((enable_if(!(flags & O_CREAT), ""))) {
+  return open_real(name, flags);
+}
+
+static inline __attribute__((always_inline))
+int open(const char* name, int flags, mode_t mode)
+    __attribute__((annotate("versioner_fortify_inline")))
+    __attribute__((overloadable))
+    __attribute__((enable_if(flags & O_CREAT, ""))) {
+  return open_real(name, flags, mode);
+}
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/tools/versioner/tests/fortify_inline/platforms/libc.map.txt b/tools/versioner/tests/fortify_inline/platforms/libc.map.txt
new file mode 100644
index 0000000..2f09034
--- /dev/null
+++ b/tools/versioner/tests/fortify_inline/platforms/libc.map.txt
@@ -0,0 +1,4 @@
+LIBC {
+  global:
+    open;
+};
diff --git a/tools/versioner/tests/fortify_inline/run.sh b/tools/versioner/tests/fortify_inline/run.sh
new file mode 100644
index 0000000..9bfbe6d
--- /dev/null
+++ b/tools/versioner/tests/fortify_inline/run.sh
@@ -0,0 +1 @@
+versioner headers -p platforms -r arm -a 9 -a 12 -i
\ No newline at end of file