Merge changes I578d36a1,Id17508ab,I385f312b

* changes:
  Create linker_log[_va_list] functions
  Validate defined versions in prelink_image
  Prelink each library only once
diff --git a/benchmarks/spawn/Android.bp b/benchmarks/spawn/Android.bp
index ecce8e8..5be8599 100644
--- a/benchmarks/spawn/Android.bp
+++ b/benchmarks/spawn/Android.bp
@@ -29,7 +29,10 @@
 cc_benchmark {
     name: "bionic-spawn-benchmarks",
     srcs: ["spawn_benchmarks.cpp"],
-    static_libs: ["libbase"],
+    static_libs: [
+        "libbase",
+        "liblog",
+    ],
 
     // Install these binaries in the same directory as the main benchmark binary.
     data: [
@@ -40,9 +43,15 @@
 
     host_supported: true,
     target: {
-        darwin: { enabled: false },
-        windows: { enabled: false },
-        linux_glibc_x86: { enabled: false },
+        darwin: {
+            enabled: false,
+        },
+        windows: {
+            enabled: false,
+        },
+        linux_glibc_x86: {
+            enabled: false,
+        },
     },
 }
 
@@ -51,15 +60,25 @@
 
     compile_multilib: "both",
     multilib: {
-        lib32: { suffix: "32" },
-        lib64: { suffix: "64" },
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
     },
 
     host_supported: true,
     target: {
-        darwin: { enabled: false },
-        windows: { enabled: false },
-        linux_glibc_x86: { enabled: false },
+        darwin: {
+            enabled: false,
+        },
+        windows: {
+            enabled: false,
+        },
+        linux_glibc_x86: {
+            enabled: false,
+        },
     },
 }
 
@@ -77,7 +96,7 @@
                 "-Wl,--rpath,${ORIGIN}/../../lib64",
             ],
         },
-    }
+    },
 }
 
 cc_binary {
diff --git a/libc/Android.bp b/libc/Android.bp
index 6d4b719..8284174 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1403,6 +1403,7 @@
         "libc_native_allocator_defaults",
     ],
     srcs: libc_common_src_files + [
+        "bionic/heap_tagging.cpp",
         "bionic/malloc_common.cpp",
         "bionic/malloc_limit.cpp",
     ],
@@ -1608,6 +1609,7 @@
     srcs: [
         "arch-common/bionic/crtbegin_so.c",
         "arch-common/bionic/crtbrand.S",
+        "bionic/heap_tagging.cpp",
         "bionic/icu.cpp",
         "bionic/malloc_common.cpp",
         "bionic/malloc_common_dynamic.cpp",
@@ -1623,6 +1625,7 @@
 filegroup {
     name: "libc_sources_static",
     srcs: [
+        "bionic/heap_tagging.cpp",
         "bionic/malloc_common.cpp",
         "bionic/malloc_limit.cpp",
     ],
@@ -2569,6 +2572,7 @@
 cc_defaults {
     name: "libc_scudo_wrapper_defaults",
     srcs: [
+        "bionic/heap_tagging.cpp",
         "bionic/malloc_common.cpp",
         "bionic/malloc_common_dynamic.cpp",
         "bionic/malloc_heapprofd.cpp",
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 21ebdbd..517d5f9 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -217,7 +217,7 @@
 int           nanosleep(const struct timespec*, struct timespec*)   all
 int           clock_settime(clockid_t, const struct timespec*)  all
 int           __clock_nanosleep:clock_nanosleep(clockid_t, int, const struct timespec*, struct timespec*)  all
-int           getitimer(int, const struct itimerval*)   all
+int           getitimer(int, struct itimerval*)   all
 int           setitimer(int, const struct itimerval*, struct itimerval*)  all
 int           __timer_create:timer_create(clockid_t clockid, struct sigevent* evp, __kernel_timer_t* timerid)    all
 int           __timer_settime:timer_settime(__kernel_timer_t, int, const struct itimerspec*, struct itimerspec*) all
@@ -249,8 +249,8 @@
 int           __accept4:accept4(int, struct sockaddr*, socklen_t*, int)  arm,arm64,mips,mips64,x86_64
 int           getsockname(int, struct sockaddr*, socklen_t*)  arm,arm64,mips,mips64,x86_64
 int           getpeername(int, struct sockaddr*, socklen_t*)  arm,arm64,mips,mips64,x86_64
-int           __sendto:sendto(int, const void*, size_t, int, const struct sockaddr*, socklen_t)  arm,arm64,mips,mips64,x86_64
-int           recvfrom(int, void*, size_t, unsigned int, struct sockaddr*, socklen_t*)  arm,arm64,mips,mips64,x86_64
+ssize_t       __sendto:sendto(int, const void*, size_t, int, const struct sockaddr*, socklen_t)  arm,arm64,mips,mips64,x86_64
+ssize_t       recvfrom(int, void*, size_t, unsigned int, struct sockaddr*, socklen_t*)  arm,arm64,mips,mips64,x86_64
 int           shutdown(int, int)  arm,arm64,mips,mips64,x86_64
 int           setsockopt(int, int, int, const void*, socklen_t)  arm,arm64,mips,mips64,x86_64
 int           getsockopt(int, int, int, void*, socklen_t*)    arm,arm64,mips,mips64,x86_64
@@ -267,8 +267,8 @@
 int           getsockname:socketcall:6(int, struct sockaddr*, socklen_t*)  x86
 int           getpeername:socketcall:7(int, struct sockaddr*, socklen_t*)  x86
 int           socketpair:socketcall:8(int, int, int, int*)    x86
-int           __sendto:socketcall:11(int, const void*, size_t, int, const struct sockaddr*, socklen_t)  x86
-int           recvfrom:socketcall:12(int, void*, size_t, unsigned int, struct sockaddr*, socklen_t*)  x86
+ssize_t       __sendto:socketcall:11(int, const void*, size_t, int, const struct sockaddr*, socklen_t)  x86
+ssize_t       recvfrom:socketcall:12(int, void*, size_t, unsigned int, struct sockaddr*, socklen_t*)  x86
 int           shutdown:socketcall:13(int, int)  x86
 int           setsockopt:socketcall:14(int, int, int, const void*, socklen_t)  x86
 int           getsockopt:socketcall:15(int, int, int, void*, socklen_t*)    x86
@@ -340,7 +340,7 @@
 int __sync_file_range2:sync_file_range2(int, unsigned int, off64_t, off64_t) arm
 
 pid_t wait4(pid_t, int*, int, struct rusage*)  all
-int __waitid:waitid(int, pid_t, struct siginfo_t*, int, void*)  all
+int __waitid:waitid(int, pid_t, siginfo_t*, int, void*)  all
 
 # ARM-specific
 int     __set_tls:__ARM_NR_set_tls(void*)                                 arm
@@ -355,8 +355,8 @@
 
 # vdso stuff.
 int __clock_getres:clock_getres(clockid_t, struct timespec*) all
-int __clock_gettime:clock_gettime(clockid_t, timespec*) all
-int __gettimeofday:gettimeofday(timeval*, timezone*) all
+int __clock_gettime:clock_gettime(clockid_t, struct timespec*) all
+int __gettimeofday:gettimeofday(struct timeval*, struct timezone*) all
 
 # <sys/random.h>
 ssize_t getrandom(void*, size_t, unsigned) all
diff --git a/libc/bionic/heap_tagging.cpp b/libc/bionic/heap_tagging.cpp
new file mode 100644
index 0000000..7c30c19
--- /dev/null
+++ b/libc/bionic/heap_tagging.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "heap_tagging.h"
+#include "malloc_common.h"
+
+#include <platform/bionic/malloc.h>
+
+static HeapTaggingLevel heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
+
+bool SetHeapTaggingLevel(void* arg, size_t arg_size) {
+  if (arg_size != sizeof(HeapTaggingLevel)) {
+    return false;
+  }
+
+  auto tag_level = *reinterpret_cast<HeapTaggingLevel*>(arg);
+  switch (tag_level) {
+    case M_HEAP_TAGGING_LEVEL_NONE:
+      break;
+    default:
+      error_log("SetHeapTaggingLevel: unknown tagging level");
+      return false;
+  }
+  heap_tagging_level = tag_level;
+  info_log("SetHeapTaggingLevel: tag level set to %d", tag_level);
+  return true;
+}
diff --git a/libc/bionic/heap_tagging.h b/libc/bionic/heap_tagging.h
new file mode 100644
index 0000000..da4c68c
--- /dev/null
+++ b/libc/bionic/heap_tagging.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <stddef.h>
+
+bool SetHeapTaggingLevel(void* arg, size_t arg_size);
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index a0da3db..30c9cc7 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -41,6 +41,7 @@
 #include <private/bionic_config.h>
 #include <platform/bionic/malloc.h>
 
+#include "heap_tagging.h"
 #include "malloc_common.h"
 #include "malloc_limit.h"
 
@@ -275,6 +276,9 @@
   if (opcode == M_SET_ALLOCATION_LIMIT_BYTES) {
     return LimitEnable(arg, arg_size);
   }
+  if (opcode == M_SET_HEAP_TAGGING_LEVEL) {
+    return SetHeapTaggingLevel(arg, arg_size);
+  }
   errno = ENOTSUP;
   return false;
 }
diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp
index eec49a4..8068f4e 100644
--- a/libc/bionic/malloc_common_dynamic.cpp
+++ b/libc/bionic/malloc_common_dynamic.cpp
@@ -64,6 +64,7 @@
 
 #include <sys/system_properties.h>
 
+#include "heap_tagging.h"
 #include "malloc_common.h"
 #include "malloc_common_dynamic.h"
 #include "malloc_heapprofd.h"
@@ -499,6 +500,9 @@
     }
     return FreeMallocLeakInfo(reinterpret_cast<android_mallopt_leak_info_t*>(arg));
   }
+  if (opcode == M_SET_HEAP_TAGGING_LEVEL) {
+    return SetHeapTaggingLevel(arg, arg_size);
+  }
   return HeapprofdMallopt(opcode, arg, arg_size);
 }
 // =============================================================================
diff --git a/libc/include/android/versioning.h b/libc/include/android/versioning.h
index d60957f..1948890 100644
--- a/libc/include/android/versioning.h
+++ b/libc/include/android/versioning.h
@@ -16,6 +16,10 @@
 
 #pragma once
 
+// The `annotate` attribute always pulls the annotated (inline) function into the object files, thus
+// we should only annotate headers when we are running versioner.
+#if defined(__BIONIC_VERSIONER)
+
 #define __INTRODUCED_IN(api_level) __attribute__((annotate("introduced_in=" #api_level)))
 #define __DEPRECATED_IN(api_level) __attribute__((annotate("deprecated_in=" #api_level)))
 #define __REMOVED_IN(api_level) __attribute__((annotate("obsoleted_in=" #api_level)))
@@ -26,3 +30,20 @@
 #define __INTRODUCED_IN_MIPS(api_level) __attribute__((annotate("introduced_in_mips=" #api_level)))
 
 #define __VERSIONER_NO_GUARD __attribute__((annotate("versioner_no_guard")))
+#define __VERSIONER_FORTIFY_INLINE __attribute__((annotate("versioner_fortify_inline")))
+
+#else
+
+#define __INTRODUCED_IN(api_level)
+#define __DEPRECATED_IN(api_level)
+#define __REMOVED_IN(api_level)
+#define __INTRODUCED_IN_32(api_level)
+#define __INTRODUCED_IN_64(api_level)
+#define __INTRODUCED_IN_ARM(api_level)
+#define __INTRODUCED_IN_X86(api_level)
+#define __INTRODUCED_IN_MIPS(api_level)
+
+#define __VERSIONER_NO_GUARD
+#define __VERSIONER_FORTIFY_INLINE
+
+#endif  // defined(__BIONIC_VERSIONER)
diff --git a/libc/include/bits/fortify/socket.h b/libc/include/bits/fortify/socket.h
index 78d4013..9e7df6d 100644
--- a/libc/include/bits/fortify/socket.h
+++ b/libc/include/bits/fortify/socket.h
@@ -57,7 +57,7 @@
     __overloadable
     __clang_error_if(__bos_unevaluated_lt(__bos0(buf), len),
                      "'sendto' called with size bigger than buffer") {
-#if __ANDROID_API__ >= 25 && __BIONIC_FORTIFY_RUNTIME_CHECKS_ENABLED
+#if __ANDROID_API__ >= 26 && __BIONIC_FORTIFY_RUNTIME_CHECKS_ENABLED
   size_t bos = __bos0(buf);
 
   if (!__bos_trivially_ge(bos, len)) {
diff --git a/libc/include/paths.h b/libc/include/paths.h
index 0aa4d93..cfbc5b3 100644
--- a/libc/include/paths.h
+++ b/libc/include/paths.h
@@ -47,7 +47,7 @@
 #define _PATH_CONSOLE "/dev/console"
 
 /** Default shell search path. */
-#define _PATH_DEFPATH "/product/bin:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin"
+#define _PATH_DEFPATH "/product/bin:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/system_ext/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin"
 
 /** Path to the directory containing device files. */
 #define _PATH_DEV "/dev/"
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
index eb30690..9e214e5 100644
--- a/libc/include/sys/cdefs.h
+++ b/libc/include/sys/cdefs.h
@@ -277,7 +277,7 @@
  * Because clang-FORTIFY uses overloads, we can't mark functions as `extern
  * inline` without making them available externally.
  */
-#  define __BIONIC_FORTIFY_INLINE static __inline__ __always_inline
+#  define __BIONIC_FORTIFY_INLINE static __inline__ __always_inline __VERSIONER_FORTIFY_INLINE
 /*
  * We should use __BIONIC_FORTIFY_VARIADIC instead of __BIONIC_FORTIFY_INLINE
  * for variadic functions because compilers cannot inline them.
diff --git a/libc/platform/bionic/malloc.h b/libc/platform/bionic/malloc.h
index 9c602ea..70fd273 100644
--- a/libc/platform/bionic/malloc.h
+++ b/libc/platform/bionic/malloc.h
@@ -29,6 +29,7 @@
 #pragma once
 
 #include <stdbool.h>
+#include <stdint.h>
 
 // Structures for android_mallopt.
 
@@ -84,6 +85,18 @@
   //   arg_size = sizeof(android_mallopt_leak_info_t)
   M_FREE_MALLOC_LEAK_INFO = 7,
 #define M_FREE_MALLOC_LEAK_INFO M_FREE_MALLOC_LEAK_INFO
+  // Change the heap tagging state. The program must be single threaded at the point when the
+  // android_mallopt function is called.
+  //   arg = HeapTaggingLevel*
+  //   arg_size = sizeof(HeapTaggingLevel)
+  M_SET_HEAP_TAGGING_LEVEL = 8,
+#define M_SET_HEAP_TAGGING_LEVEL M_SET_HEAP_TAGGING_LEVEL
+};
+
+enum HeapTaggingLevel {
+  // Disable heap tagging. The program must use prctl(PR_SET_TAGGED_ADDR_CTRL) to disable memory tag
+  // checks before disabling heap tagging. Heap tagging may not be re-enabled after being disabled.
+  M_HEAP_TAGGING_LEVEL_NONE = 0,
 };
 
 // Manipulates bionic-specific handling of memory allocation APIs such as
diff --git a/libm/Android.bp b/libm/Android.bp
index bf05b17..801129a 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -9,7 +9,7 @@
     recovery_available: true,
     static_ndk_lib: true,
 
-    whole_static_libs: ["libarm-optimized-routines"],
+    whole_static_libs: ["libarm-optimized-routines-math"],
 
     srcs: [
         "upstream-freebsd/lib/msun/bsdsrc/b_exp.c",
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 87335e4..10833be 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -4194,11 +4194,13 @@
   // we also need vdso to be available for all namespaces (if present)
   soinfo* vdso = solist_get_vdso();
   for (auto it : namespaces) {
-    it.second->add_soinfo(ld_android_so);
-    if (vdso != nullptr) {
-      it.second->add_soinfo(vdso);
+    if (it.second != &g_default_namespace) {
+      it.second->add_soinfo(ld_android_so);
+      if (vdso != nullptr) {
+        it.second->add_soinfo(vdso);
+      }
+      // somain and ld_preloads are added to these namespaces after LD_PRELOAD libs are linked
     }
-    // somain and ld_preloads are added to these namespaces after LD_PRELOAD libs are linked
   }
 
   set_application_target_sdk_version(config->target_sdk_version());
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index a0cda1b..75abbd2 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -853,6 +853,20 @@
   ASSERT_EQ(ENOMEM, errno);
 }
 
+// Inspired by https://github.com/landley/toybox/issues/163.
+TEST(STDIO_TEST, printf_NULL) {
+  char buf[128];
+  char* null = nullptr;
+  EXPECT_EQ(4, snprintf(buf, sizeof(buf), "<%*.*s>", 2, 2, null));
+  EXPECT_STREQ("<(n>", buf);
+  EXPECT_EQ(8, snprintf(buf, sizeof(buf), "<%*.*s>", 2, 8, null));
+  EXPECT_STREQ("<(null)>", buf);
+  EXPECT_EQ(10, snprintf(buf, sizeof(buf), "<%*.*s>", 8, 2, null));
+  EXPECT_STREQ("<      (n>", buf);
+  EXPECT_EQ(10, snprintf(buf, sizeof(buf), "<%*.*s>", 8, 8, null));
+  EXPECT_STREQ("<  (null)>", buf);
+}
+
 TEST(STDIO_TEST, fprintf) {
   TemporaryFile tf;
 
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/Driver.cpp b/tools/versioner/src/Driver.cpp
index 927a0f5..184c3d4 100644
--- a/tools/versioner/src/Driver.cpp
+++ b/tools/versioner/src/Driver.cpp
@@ -125,6 +125,7 @@
   cmd.push_back(arch_targets[type.arch]);
 
   cmd.push_back("-DANDROID");
+  cmd.push_back("-D__BIONIC_VERSIONER=1");
   cmd.push_back("-D__ANDROID_API__="s + std::to_string(type.api_level));
   cmd.push_back("-D_FORTIFY_SOURCE=2");
   cmd.push_back("-D_GNU_SOURCE");
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