Merge "Add uc_sigmask64."
diff --git a/benchmarks/util.h b/benchmarks/util.h
index 3225bc2..d9e10f4 100644
--- a/benchmarks/util.h
+++ b/benchmarks/util.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef _BIONIC_BENCHMARKS_UTIL_H_
-#define _BIONIC_BENCHMARKS_UTIL_H_
+#pragma once
 
 #include <map>
 #include <mutex>
@@ -62,5 +61,3 @@
 char* GetAlignedPtrFilled(std::vector<char>* buf, size_t alignment, size_t nbytes, char fill_byte);
 
 bool LockToCPU(long cpu_to_lock);
-
-#endif // _BIONIC_BENCHMARKS_UTIL_H
diff --git a/libc/async_safe/include/async_safe/log.h b/libc/async_safe/include/async_safe/log.h
index 10833e4..415b48e 100644
--- a/libc/async_safe/include/async_safe/log.h
+++ b/libc/async_safe/include/async_safe/log.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _ASYNC_SAFE_LOG_LOG_H
-#define _ASYNC_SAFE_LOG_LOG_H
+#pragma once
 
 #include <sys/cdefs.h>
 #include <stdarg.h>
@@ -104,5 +103,3 @@
   } while(0)
 
 __END_DECLS
-
-#endif
diff --git a/libc/bionic/bionic_netlink.h b/libc/bionic/bionic_netlink.h
index bc0e3f0..a21200e 100644
--- a/libc/bionic/bionic_netlink.h
+++ b/libc/bionic/bionic_netlink.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef BIONIC_NETLINK_H
-#define BIONIC_NETLINK_H
+#pragma once
 
 #include <sys/types.h>
 
@@ -49,5 +48,3 @@
   char* data_;
   size_t size_;
 };
-
-#endif
diff --git a/libc/bionic/grp_pwd_file.h b/libc/bionic/grp_pwd_file.h
index ae8cd98..93dd852 100644
--- a/libc/bionic/grp_pwd_file.h
+++ b/libc/bionic/grp_pwd_file.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef GRP_PWD_FILE_H
-#define GRP_PWD_FILE_H
+#pragma once
 
 #include <grp.h>
 #include <pwd.h>
@@ -93,5 +92,3 @@
  private:
   MmapFile mmap_file_;
 };
-
-#endif
diff --git a/libc/bionic/jemalloc.h b/libc/bionic/jemalloc.h
index f7e8770..79a4f72 100644
--- a/libc/bionic/jemalloc.h
+++ b/libc/bionic/jemalloc.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef LIBC_BIONIC_JEMALLOC_H_
-#define LIBC_BIONIC_JEMALLOC_H_
+#pragma once
 
 #include <jemalloc/jemalloc.h>
 #include <malloc.h>  // For struct mallinfo.
@@ -35,5 +34,3 @@
 void* je_pvalloc(size_t);
 
 __END_DECLS
-
-#endif  // LIBC_BIONIC_DLMALLOC_H_
diff --git a/libc/bionic/libc_init_common.h b/libc/bionic/libc_init_common.h
index 5066652..6ce4d10 100644
--- a/libc/bionic/libc_init_common.h
+++ b/libc/bionic/libc_init_common.h
@@ -25,8 +25,8 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#ifndef LIBC_INIT_COMMON_H
-#define LIBC_INIT_COMMON_H
+
+#pragma once
 
 #include <sys/cdefs.h>
 
@@ -59,5 +59,3 @@
 __LIBC_HIDDEN__ void __libc_init_AT_SECURE(KernelArgumentBlock& args);
 
 #endif
-
-#endif
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp
index 940c418..1ea4ac1 100644
--- a/libc/bionic/malloc_common.cpp
+++ b/libc/bionic/malloc_common.cpp
@@ -72,6 +72,12 @@
     Malloc(aligned_alloc),
   };
 
+// Malloc hooks.
+void* (*volatile __malloc_hook)(size_t, const void*);
+void* (*volatile __realloc_hook)(void*, size_t, const void*);
+void (*volatile __free_hook)(void*, const void*);
+void* (*volatile __memalign_hook)(size_t, size_t, const void*);
+
 // In a VM process, this is set to 1 after fork()ing out of zygote.
 int gMallocLeakZygoteChild = 0;
 
@@ -190,17 +196,30 @@
 
 extern "C" int __cxa_atexit(void (*func)(void *), void *arg, void *dso);
 
+static const char* HOOKS_SHARED_LIB = "libc_malloc_hooks.so";
+static const char* HOOKS_PROPERTY_ENABLE = "libc.debug.hooks.enable";
+static const char* HOOKS_ENV_ENABLE = "LIBC_HOOKS_ENABLE";
+
 static const char* DEBUG_SHARED_LIB = "libc_malloc_debug.so";
-static const char* DEBUG_MALLOC_PROPERTY_OPTIONS = "libc.debug.malloc.options";
-static const char* DEBUG_MALLOC_PROPERTY_PROGRAM = "libc.debug.malloc.program";
-static const char* DEBUG_MALLOC_ENV_OPTIONS = "LIBC_DEBUG_MALLOC_OPTIONS";
+static const char* DEBUG_PROPERTY_OPTIONS = "libc.debug.malloc.options";
+static const char* DEBUG_PROPERTY_PROGRAM = "libc.debug.malloc.program";
+static const char* DEBUG_ENV_OPTIONS = "LIBC_DEBUG_MALLOC_OPTIONS";
 
-static void* libc_malloc_impl_handle = nullptr;
+enum FunctionEnum : uint8_t {
+  FUNC_INITIALIZE,
+  FUNC_FINALIZE,
+  FUNC_GET_MALLOC_LEAK_INFO,
+  FUNC_FREE_MALLOC_LEAK_INFO,
+  FUNC_MALLOC_BACKTRACE,
+  FUNC_LAST,
+};
+static void* g_functions[FUNC_LAST];
 
-static void (*g_debug_finalize_func)();
-static void (*g_debug_get_malloc_leak_info_func)(uint8_t**, size_t*, size_t*, size_t*, size_t*);
-static void (*g_debug_free_malloc_leak_info_func)(uint8_t*);
-static ssize_t (*g_debug_malloc_backtrace_func)(void*, uintptr_t*, size_t);
+typedef void (*finalize_func_t)();
+typedef bool (*init_func_t)(const MallocDispatch*, int*, const char*);
+typedef void (*get_malloc_leak_info_func_t)(uint8_t**, size_t*, size_t*, size_t*, size_t*);
+typedef void (*free_malloc_leak_info_func_t)(uint8_t*);
+typedef ssize_t (*malloc_backtrace_func_t)(void*, uintptr_t*, size_t);
 
 // =============================================================================
 // Log functions
@@ -225,17 +244,20 @@
 // "*backtrace_size" is set to the maximum number of entries in the back trace
 extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overall_size,
     size_t* info_size, size_t* total_memory, size_t* backtrace_size) {
-  if (g_debug_get_malloc_leak_info_func == nullptr) {
+  void* func = g_functions[FUNC_GET_MALLOC_LEAK_INFO];
+  if (func == nullptr) {
     return;
   }
-  g_debug_get_malloc_leak_info_func(info, overall_size, info_size, total_memory, backtrace_size);
+  reinterpret_cast<get_malloc_leak_info_func_t>(func)(info, overall_size, info_size, total_memory,
+                                                      backtrace_size);
 }
 
 extern "C" void free_malloc_leak_info(uint8_t* info) {
-  if (g_debug_free_malloc_leak_info_func == nullptr) {
+  void* func = g_functions[FUNC_FREE_MALLOC_LEAK_INFO];
+  if (func == nullptr) {
     return;
   }
-  g_debug_free_malloc_leak_info_func(info);
+  reinterpret_cast<free_malloc_leak_info_func_t>(func)(info);
 }
 
 // =============================================================================
@@ -252,66 +274,56 @@
   return true;
 }
 
-static bool InitMalloc(void* malloc_impl_handler, MallocDispatch* table, const char* prefix) {
-  if (!InitMallocFunction<MallocCalloc>(malloc_impl_handler, &table->calloc,
-                                        prefix, "calloc")) {
+static bool InitMallocFunctions(void* impl_handler, MallocDispatch* table, const char* prefix) {
+  if (!InitMallocFunction<MallocCalloc>(impl_handler, &table->calloc, prefix, "calloc")) {
     return false;
   }
-  if (!InitMallocFunction<MallocFree>(malloc_impl_handler, &table->free,
-                                      prefix, "free")) {
+  if (!InitMallocFunction<MallocFree>(impl_handler, &table->free, prefix, "free")) {
     return false;
   }
-  if (!InitMallocFunction<MallocMallinfo>(malloc_impl_handler, &table->mallinfo,
-                                          prefix, "mallinfo")) {
+  if (!InitMallocFunction<MallocMallinfo>(impl_handler, &table->mallinfo, prefix, "mallinfo")) {
     return false;
   }
-  if (!InitMallocFunction<MallocMallopt>(malloc_impl_handler, &table->mallopt,
-                                         prefix, "mallopt")) {
+  if (!InitMallocFunction<MallocMallopt>(impl_handler, &table->mallopt, prefix, "mallopt")) {
     return false;
   }
-  if (!InitMallocFunction<MallocMalloc>(malloc_impl_handler, &table->malloc,
-                                        prefix, "malloc")) {
+  if (!InitMallocFunction<MallocMalloc>(impl_handler, &table->malloc, prefix, "malloc")) {
     return false;
   }
-  if (!InitMallocFunction<MallocMallocUsableSize>(
-      malloc_impl_handler, &table->malloc_usable_size, prefix, "malloc_usable_size")) {
+  if (!InitMallocFunction<MallocMallocUsableSize>(impl_handler, &table->malloc_usable_size, prefix,
+                                                  "malloc_usable_size")) {
     return false;
   }
-  if (!InitMallocFunction<MallocMemalign>(malloc_impl_handler, &table->memalign,
-                                          prefix, "memalign")) {
+  if (!InitMallocFunction<MallocMemalign>(impl_handler, &table->memalign, prefix, "memalign")) {
     return false;
   }
-  if (!InitMallocFunction<MallocPosixMemalign>(malloc_impl_handler, &table->posix_memalign,
-                                               prefix, "posix_memalign")) {
+  if (!InitMallocFunction<MallocPosixMemalign>(impl_handler, &table->posix_memalign, prefix,
+                                               "posix_memalign")) {
     return false;
   }
-  if (!InitMallocFunction<MallocAlignedAlloc>(malloc_impl_handler, &table->aligned_alloc,
+  if (!InitMallocFunction<MallocAlignedAlloc>(impl_handler, &table->aligned_alloc,
                                               prefix, "aligned_alloc")) {
     return false;
   }
-  if (!InitMallocFunction<MallocRealloc>(malloc_impl_handler, &table->realloc,
-                                         prefix, "realloc")) {
+  if (!InitMallocFunction<MallocRealloc>(impl_handler, &table->realloc, prefix, "realloc")) {
     return false;
   }
-  if (!InitMallocFunction<MallocIterate>(malloc_impl_handler, &table->iterate,
-                                         prefix, "iterate")) {
+  if (!InitMallocFunction<MallocIterate>(impl_handler, &table->iterate, prefix, "iterate")) {
     return false;
   }
-  if (!InitMallocFunction<MallocMallocDisable>(malloc_impl_handler, &table->malloc_disable,
-                                         prefix, "malloc_disable")) {
+  if (!InitMallocFunction<MallocMallocDisable>(impl_handler, &table->malloc_disable, prefix,
+                                               "malloc_disable")) {
     return false;
   }
-  if (!InitMallocFunction<MallocMallocEnable>(malloc_impl_handler, &table->malloc_enable,
-                                         prefix, "malloc_enable")) {
+  if (!InitMallocFunction<MallocMallocEnable>(impl_handler, &table->malloc_enable, prefix,
+                                              "malloc_enable")) {
     return false;
   }
 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
-  if (!InitMallocFunction<MallocPvalloc>(malloc_impl_handler, &table->pvalloc,
-                                         prefix, "pvalloc")) {
+  if (!InitMallocFunction<MallocPvalloc>(impl_handler, &table->pvalloc, prefix, "pvalloc")) {
     return false;
   }
-  if (!InitMallocFunction<MallocValloc>(malloc_impl_handler, &table->valloc,
-                                        prefix, "valloc")) {
+  if (!InitMallocFunction<MallocValloc>(impl_handler, &table->valloc, prefix, "valloc")) {
     return false;
   }
 #endif
@@ -328,102 +340,114 @@
   fclose(stdout);
   fclose(stderr);
 
-  g_debug_finalize_func();
+  reinterpret_cast<finalize_func_t>(g_functions[FUNC_FINALIZE])();
+}
+
+static bool CheckLoadMallocHooks(char** options) {
+  char* env = getenv(HOOKS_ENV_ENABLE);
+  if ((env == nullptr || env[0] == '\0' || env[0] == '0') &&
+    (__system_property_get(HOOKS_PROPERTY_ENABLE, *options) == 0 || *options[0] == '\0' || *options[0] == '0')) {
+    return false;
+  }
+  *options = nullptr;
+  return true;
+}
+
+static bool CheckLoadMallocDebug(char** options) {
+  // If DEBUG_MALLOC_ENV_OPTIONS is set then it overrides the system properties.
+  char* env = getenv(DEBUG_ENV_OPTIONS);
+  if (env == nullptr || env[0] == '\0') {
+    if (__system_property_get(DEBUG_PROPERTY_OPTIONS, *options) == 0 || *options[0] == '\0') {
+      return false;
+    }
+
+    // Check to see if only a specific program should have debug malloc enabled.
+    char program[PROP_VALUE_MAX];
+    if (__system_property_get(DEBUG_PROPERTY_PROGRAM, program) != 0 &&
+        strstr(getprogname(), program) == nullptr) {
+      return false;
+    }
+  } else {
+    *options = env;
+  }
+  return true;
+}
+
+static void ClearGlobalFunctions() {
+  for (size_t i = 0; i < FUNC_LAST; i++) {
+    g_functions[i] = nullptr;
+  }
+}
+
+static void* LoadSharedLibrary(const char* shared_lib, const char* prefix, MallocDispatch* dispatch_table) {
+  void* impl_handle = dlopen(shared_lib, RTLD_NOW | RTLD_LOCAL);
+  if (impl_handle == nullptr) {
+    error_log("%s: Unable to open shared library %s: %s", getprogname(), shared_lib, dlerror());
+    return nullptr;
+  }
+
+  static constexpr const char* names[] = {
+    "initialize",
+    "finalize",
+    "get_malloc_leak_info",
+    "free_malloc_leak_info",
+    "malloc_backtrace",
+  };
+  for (size_t i = 0; i < FUNC_LAST; i++) {
+    char symbol[128];
+    snprintf(symbol, sizeof(symbol), "%s_%s", prefix, names[i]);
+    g_functions[i] = dlsym(impl_handle, symbol);
+    if (g_functions[i] == nullptr) {
+      error_log("%s: %s routine not found in %s", getprogname(), symbol, shared_lib);
+      dlclose(impl_handle);
+      ClearGlobalFunctions();
+      return nullptr;
+    }
+  }
+
+  if (!InitMallocFunctions(impl_handle, dispatch_table, prefix)) {
+    dlclose(impl_handle);
+    ClearGlobalFunctions();
+    return nullptr;
+  }
+
+  return impl_handle;
 }
 
 // Initializes memory allocation framework once per process.
 static void malloc_init_impl(libc_globals* globals) {
-  char value[PROP_VALUE_MAX];
-
-  // If DEBUG_MALLOC_ENV_OPTIONS is set then it overrides the system properties.
-  const char* options = getenv(DEBUG_MALLOC_ENV_OPTIONS);
-  if (options == nullptr || options[0] == '\0') {
-    if (__system_property_get(DEBUG_MALLOC_PROPERTY_OPTIONS, value) == 0 || value[0] == '\0') {
-      return;
-    }
-    options = value;
-
-    // Check to see if only a specific program should have debug malloc enabled.
-    char program[PROP_VALUE_MAX];
-    if (__system_property_get(DEBUG_MALLOC_PROPERTY_PROGRAM, program) != 0 &&
-        strstr(getprogname(), program) == nullptr) {
-      return;
-    }
-  }
-
-  // Load the debug malloc shared library.
-  void* malloc_impl_handle = dlopen(DEBUG_SHARED_LIB, RTLD_NOW | RTLD_LOCAL);
-  if (malloc_impl_handle == nullptr) {
-    error_log("%s: Unable to open debug malloc shared library %s: %s",
-              getprogname(), DEBUG_SHARED_LIB, dlerror());
+  const char* prefix;
+  const char* shared_lib;
+  char prop[PROP_VALUE_MAX];
+  char* options = prop;
+  // Prefer malloc debug since it existed first and is a more complete
+  // malloc interceptor than the hooks.
+  if (CheckLoadMallocDebug(&options)) {
+    prefix = "debug";
+    shared_lib = DEBUG_SHARED_LIB;
+  } else if (CheckLoadMallocHooks(&options)) {
+    prefix = "hooks";
+    shared_lib = HOOKS_SHARED_LIB;
+  } else {
     return;
   }
 
-  // Initialize malloc debugging in the loaded module.
-  auto init_func = reinterpret_cast<bool (*)(const MallocDispatch*, int*, const char*)>(
-      dlsym(malloc_impl_handle, "debug_initialize"));
-  if (init_func == nullptr) {
-    error_log("%s: debug_initialize routine not found in %s", getprogname(), DEBUG_SHARED_LIB);
-    dlclose(malloc_impl_handle);
+  MallocDispatch dispatch_table;
+  void* impl_handle = LoadSharedLibrary(shared_lib, prefix, &dispatch_table);
+  if (impl_handle == nullptr) {
     return;
   }
 
-  // Get the syms for the external functions.
-  void* finalize_sym = dlsym(malloc_impl_handle, "debug_finalize");
-  if (finalize_sym == nullptr) {
-    error_log("%s: debug_finalize routine not found in %s", getprogname(), DEBUG_SHARED_LIB);
-    dlclose(malloc_impl_handle);
-    return;
-  }
-
-  void* get_leak_info_sym = dlsym(malloc_impl_handle, "debug_get_malloc_leak_info");
-  if (get_leak_info_sym == nullptr) {
-    error_log("%s: debug_get_malloc_leak_info routine not found in %s", getprogname(),
-              DEBUG_SHARED_LIB);
-    dlclose(malloc_impl_handle);
-    return;
-  }
-
-  void* free_leak_info_sym = dlsym(malloc_impl_handle, "debug_free_malloc_leak_info");
-  if (free_leak_info_sym == nullptr) {
-    error_log("%s: debug_free_malloc_leak_info routine not found in %s", getprogname(),
-              DEBUG_SHARED_LIB);
-    dlclose(malloc_impl_handle);
-    return;
-  }
-
-  void* malloc_backtrace_sym = dlsym(malloc_impl_handle, "debug_malloc_backtrace");
-  if (malloc_backtrace_sym == nullptr) {
-    error_log("%s: debug_malloc_backtrace routine not found in %s", getprogname(),
-              DEBUG_SHARED_LIB);
-    dlclose(malloc_impl_handle);
-    return;
-  }
-
+  init_func_t init_func = reinterpret_cast<init_func_t>(g_functions[FUNC_INITIALIZE]);
   if (!init_func(&__libc_malloc_default_dispatch, &gMallocLeakZygoteChild, options)) {
-    dlclose(malloc_impl_handle);
+    dlclose(impl_handle);
+    ClearGlobalFunctions();
     return;
   }
 
-  MallocDispatch malloc_dispatch_table;
-  if (!InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "debug")) {
-    auto finalize_func = reinterpret_cast<void (*)()>(finalize_sym);
-    finalize_func();
-    dlclose(malloc_impl_handle);
-    return;
-  }
+  globals->malloc_dispatch = dispatch_table;
 
-  g_debug_finalize_func = reinterpret_cast<void (*)()>(finalize_sym);
-  g_debug_get_malloc_leak_info_func = reinterpret_cast<void (*)(
-      uint8_t**, size_t*, size_t*, size_t*, size_t*)>(get_leak_info_sym);
-  g_debug_free_malloc_leak_info_func = reinterpret_cast<void (*)(uint8_t*)>(free_leak_info_sym);
-  g_debug_malloc_backtrace_func = reinterpret_cast<ssize_t (*)(
-      void*, uintptr_t*, size_t)>(malloc_backtrace_sym);
-
-  globals->malloc_dispatch = malloc_dispatch_table;
-  libc_malloc_impl_handle = malloc_impl_handle;
-
-  info_log("%s: malloc debug enabled", getprogname());
+  info_log("%s: malloc %s enabled", getprogname(), prefix);
 
   // Use atexit to trigger the cleanup function. This avoids a problem
   // where another atexit function is used to cleanup allocated memory,
@@ -478,10 +502,11 @@
 
 #ifndef LIBC_STATIC
 extern "C" ssize_t malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count) {
-  if (g_debug_malloc_backtrace_func == nullptr) {
+  void* func = g_functions[FUNC_MALLOC_BACKTRACE];
+  if (func == nullptr) {
     return 0;
   }
-  return g_debug_malloc_backtrace_func(pointer, frames, frame_count);
+  return reinterpret_cast<malloc_backtrace_func_t>(func)(pointer, frames, frame_count);
 }
 #else
 extern "C" ssize_t malloc_backtrace(void*, uintptr_t*, size_t) {
diff --git a/libc/bionic/malloc_info.h b/libc/bionic/malloc_info.h
index 5fffae9..257fec1 100644
--- a/libc/bionic/malloc_info.h
+++ b/libc/bionic/malloc_info.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef LIBC_BIONIC_MALLOC_INFO_H_
-#define LIBC_BIONIC_MALLOC_INFO_H_
+#pragma once
 
 #include <malloc.h>
 #include <sys/cdefs.h>
@@ -28,5 +27,3 @@
 __LIBC_HIDDEN__ struct mallinfo __mallinfo_bin_info(size_t, size_t);
 
 __END_DECLS
-
-#endif // LIBC_BIONIC_MALLOC_INFO_H_
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index a4cba87..18f5aee 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -25,8 +25,8 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#ifndef _PTHREAD_INTERNAL_H_
-#define _PTHREAD_INTERNAL_H_
+
+#pragma once
 
 #include <pthread.h>
 #include <stdatomic.h>
@@ -172,5 +172,3 @@
 __LIBC_HIDDEN__ extern void __bionic_atfork_run_prepare();
 __LIBC_HIDDEN__ extern void __bionic_atfork_run_child();
 __LIBC_HIDDEN__ extern void __bionic_atfork_run_parent();
-
-#endif /* _PTHREAD_INTERNAL_H_ */
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index 80b08f6..3a678a9 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -81,6 +81,14 @@
 #define M_DECAY_TIME -100
 int mallopt(int __option, int __value) __INTRODUCED_IN(26);
 
+/*
+ * Memory Allocation Hooks
+ */
+extern void* (*volatile __malloc_hook)(size_t, const void*) __INTRODUCED_IN(28);
+extern void* (*volatile __realloc_hook)(void*, size_t, const void*) __INTRODUCED_IN(28);
+extern void (*volatile __free_hook)(void*, const void*) __INTRODUCED_IN(28);
+extern void* (*volatile __memalign_hook)(size_t, size_t, const void*) __INTRODUCED_IN(28);
+
 __END_DECLS
 
 #endif  /* LIBC_INCLUDE_MALLOC_H_ */
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index a7977eb..4586fdac 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1321,7 +1321,11 @@
 LIBC_P { # introduced=P
   global:
     __freading;
+    __free_hook;
     __fwriting;
+    __malloc_hook;
+    __memalign_hook;
+    __realloc_hook;
     aligned_alloc;
     endhostent;
     endnetent;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 1cae22b..75436ff 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1241,7 +1241,11 @@
 LIBC_P { # introduced=P
   global:
     __freading;
+    __free_hook;
     __fwriting;
+    __malloc_hook;
+    __memalign_hook;
+    __realloc_hook;
     aligned_alloc;
     endhostent;
     endnetent;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 1188a85..a8a52c3 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1346,7 +1346,11 @@
 LIBC_P { # introduced=P
   global:
     __freading;
+    __free_hook;
     __fwriting;
+    __malloc_hook;
+    __memalign_hook;
+    __realloc_hook;
     aligned_alloc;
     endhostent;
     endnetent;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index 3d95079..584807e 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1305,7 +1305,11 @@
 LIBC_P { # introduced=P
   global:
     __freading;
+    __free_hook;
     __fwriting;
+    __malloc_hook;
+    __memalign_hook;
+    __realloc_hook;
     aligned_alloc;
     endhostent;
     endnetent;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 1cae22b..75436ff 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1241,7 +1241,11 @@
 LIBC_P { # introduced=P
   global:
     __freading;
+    __free_hook;
     __fwriting;
+    __malloc_hook;
+    __memalign_hook;
+    __realloc_hook;
     aligned_alloc;
     endhostent;
     endnetent;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index bcb5feb..4498d6d 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1303,7 +1303,11 @@
 LIBC_P { # introduced=P
   global:
     __freading;
+    __free_hook;
     __fwriting;
+    __malloc_hook;
+    __memalign_hook;
+    __realloc_hook;
     aligned_alloc;
     endhostent;
     endnetent;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 1cae22b..75436ff 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1241,7 +1241,11 @@
 LIBC_P { # introduced=P
   global:
     __freading;
+    __free_hook;
     __fwriting;
+    __malloc_hook;
+    __memalign_hook;
+    __realloc_hook;
     aligned_alloc;
     endhostent;
     endnetent;
diff --git a/libc/malloc_debug/BacktraceData.h b/libc/malloc_debug/BacktraceData.h
index c8234dc..3c15348 100644
--- a/libc/malloc_debug/BacktraceData.h
+++ b/libc/malloc_debug/BacktraceData.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef DEBUG_MALLOC_BACKTRACEDATA_H
-#define DEBUG_MALLOC_BACKTRACEDATA_H
+#pragma once
 
 #include <stdint.h>
 
@@ -67,5 +66,3 @@
 
   DISALLOW_COPY_AND_ASSIGN(BacktraceData);
 };
-
-#endif // DEBUG_MALLOC_BACKTRACEDATA_H
diff --git a/libc/malloc_debug/Config.h b/libc/malloc_debug/Config.h
index 349ad77..a310e09 100644
--- a/libc/malloc_debug/Config.h
+++ b/libc/malloc_debug/Config.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef MALLOC_DEBUG_CONFIG_H
-#define MALLOC_DEBUG_CONFIG_H
+#pragma once
 
 #include <stdint.h>
 
@@ -159,5 +158,3 @@
   uint8_t front_guard_value_;
   uint8_t rear_guard_value_;
 };
-
-#endif  // MALLOC_DEBUG_CONFIG_H
diff --git a/libc/malloc_debug/DebugData.h b/libc/malloc_debug/DebugData.h
index 7228a72..9aece0b 100644
--- a/libc/malloc_debug/DebugData.h
+++ b/libc/malloc_debug/DebugData.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef DEBUG_MALLOC_DEBUGDATA_H
-#define DEBUG_MALLOC_DEBUGDATA_H
+#pragma once
 
 #include <stdint.h>
 
@@ -106,5 +105,3 @@
 };
 
 extern DebugData* g_debug;
-
-#endif // MALLOC_DEBUG_DEBUGDATA_H
diff --git a/libc/malloc_debug/FreeTrackData.h b/libc/malloc_debug/FreeTrackData.h
index 0e8c177..bd3497d 100644
--- a/libc/malloc_debug/FreeTrackData.h
+++ b/libc/malloc_debug/FreeTrackData.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef DEBUG_MALLOC_FREETRACKDATA_H
-#define DEBUG_MALLOC_FREETRACKDATA_H
+#pragma once
 
 #include <stdint.h>
 #include <pthread.h>
@@ -75,5 +74,3 @@
 
   DISALLOW_COPY_AND_ASSIGN(FreeTrackData);
 };
-
-#endif // DEBUG_MALLOC_FREETRACKDATA_H
diff --git a/libc/malloc_debug/GuardData.h b/libc/malloc_debug/GuardData.h
index ddf6ce1..7b21671 100644
--- a/libc/malloc_debug/GuardData.h
+++ b/libc/malloc_debug/GuardData.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef DEBUG_MALLOC_GUARDDATA_H
-#define DEBUG_MALLOC_GUARDDATA_H
+#pragma once
 
 #include <stdint.h>
 #include <string.h>
@@ -93,5 +92,3 @@
 
   DISALLOW_COPY_AND_ASSIGN(RearGuardData);
 };
-
-#endif // DEBUG_MALLOC_GUARDDATA_H
diff --git a/libc/malloc_debug/MapData.h b/libc/malloc_debug/MapData.h
index 895f78f..a71f96d 100644
--- a/libc/malloc_debug/MapData.h
+++ b/libc/malloc_debug/MapData.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef DEBUG_MALLOC_MAPDATA_H
-#define DEBUG_MALLOC_MAPDATA_H
+#pragma once
 
 #include <sys/cdefs.h>
 
@@ -74,5 +73,3 @@
 
   DISALLOW_COPY_AND_ASSIGN(MapData);
 };
-
-#endif  // DEBUG_MALLOC_MAPDATA_H
diff --git a/libc/malloc_debug/OptionData.h b/libc/malloc_debug/OptionData.h
index 5c2d272..3fa8e14 100644
--- a/libc/malloc_debug/OptionData.h
+++ b/libc/malloc_debug/OptionData.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef DEBUG_MALLOC_OPTIONDATA_H
-#define DEBUG_MALLOC_OPTIONDATA_H
+#pragma once
 
 // Forward Declarations
 class DebugData;
@@ -42,5 +41,3 @@
 
   DISALLOW_COPY_AND_ASSIGN(OptionData);
 };
-
-#endif // MALLOC_DEBUG_OPTIONDATA_H
diff --git a/libc/malloc_debug/RecordData.h b/libc/malloc_debug/RecordData.h
index 97ad813..021a299 100644
--- a/libc/malloc_debug/RecordData.h
+++ b/libc/malloc_debug/RecordData.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef DEBUG_MALLOC_RECORDDATA_H
-#define DEBUG_MALLOC_RECORDDATA_H
+#pragma once
 
 #include <stdint.h>
 #include <pthread.h>
@@ -173,5 +172,3 @@
 
   DISALLOW_COPY_AND_ASSIGN(RecordData);
 };
-
-#endif // DEBUG_MALLOC_RECORDDATA_H
diff --git a/libc/malloc_debug/TrackData.h b/libc/malloc_debug/TrackData.h
index 9a649b9..7201c49 100644
--- a/libc/malloc_debug/TrackData.h
+++ b/libc/malloc_debug/TrackData.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef DEBUG_MALLOC_TRACKDATA_H
-#define DEBUG_MALLOC_TRACKDATA_H
+#pragma once
 
 #include <stdint.h>
 #include <pthread.h>
@@ -75,5 +74,3 @@
 
   DISALLOW_COPY_AND_ASSIGN(TrackData);
 };
-
-#endif // DEBUG_MALLOC_TRACKDATA_H
diff --git a/libc/malloc_debug/backtrace.h b/libc/malloc_debug/backtrace.h
index f570873..92ea237 100644
--- a/libc/malloc_debug/backtrace.h
+++ b/libc/malloc_debug/backtrace.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef MALLOC_DEBUG_BACKTRACE_H
-#define MALLOC_DEBUG_BACKTRACE_H
+#pragma once
 
 #include <stdint.h>
 #include <sys/cdefs.h>
@@ -39,5 +38,3 @@
 size_t backtrace_get(uintptr_t* frames, size_t frame_count);
 void backtrace_log(const uintptr_t* frames, size_t frame_count);
 std::string backtrace_string(const uintptr_t* frames, size_t frame_count);
-
-#endif // MALLOC_DEBUG_BACKTRACE_H
diff --git a/libc/malloc_debug/debug_disable.h b/libc/malloc_debug/debug_disable.h
index 9edb4df..0049595 100644
--- a/libc/malloc_debug/debug_disable.h
+++ b/libc/malloc_debug/debug_disable.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef MALLOC_DEBUG_DISABLE_H
-#define MALLOC_DEBUG_DISABLE_H
+#pragma once
 
 #include <sys/cdefs.h>
 
@@ -60,5 +59,3 @@
 
   DISALLOW_COPY_AND_ASSIGN(ScopedDisableDebugCalls);
 };
-
-#endif  // MALLOC_DEBUG_DISABLE_H
diff --git a/libc/malloc_debug/debug_log.h b/libc/malloc_debug/debug_log.h
index ed4b541..54dd221 100644
--- a/libc/malloc_debug/debug_log.h
+++ b/libc/malloc_debug/debug_log.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef MALLOC_DEBUG_LOG_H
-#define MALLOC_DEBUG_LOG_H
+#pragma once
 
 #include <async_safe/log.h>
 
@@ -42,5 +41,3 @@
     async_safe_write_log(ANDROID_LOG_ERROR, "malloc_debug", (str))
 #define info_log(format, ...)  \
     async_safe_format_log(ANDROID_LOG_INFO, "malloc_debug", (format), ##__VA_ARGS__ )
-
-#endif  // MALLOC_DEBUG_LOG_H
diff --git a/libc/malloc_debug/malloc_debug.h b/libc/malloc_debug/malloc_debug.h
index 4a1e8da..18a6c2c 100644
--- a/libc/malloc_debug/malloc_debug.h
+++ b/libc/malloc_debug/malloc_debug.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef MALLOC_DEBUG_H
-#define MALLOC_DEBUG_H
+#pragma once
 
 #include <stdint.h>
 
@@ -70,5 +69,3 @@
 constexpr size_t FREE_TRACK_MEM_BUFFER_SIZE = 4096;
 
 extern const MallocDispatch* g_dispatch;
-
-#endif // MALLOC_DEBUG_H
diff --git a/libc/malloc_hooks/Android.bp b/libc/malloc_hooks/Android.bp
new file mode 100644
index 0000000..d4b5a2a
--- /dev/null
+++ b/libc/malloc_hooks/Android.bp
@@ -0,0 +1,66 @@
+// ==============================================================
+// libc_malloc_hooks.so
+// ==============================================================
+cc_library {
+    name: "libc_malloc_hooks",
+
+    srcs: [
+        "malloc_hooks.cpp",
+    ],
+
+    static_libs: [
+        "libasync_safe",
+    ],
+
+    multilib: {
+        lib32: {
+            version_script: "exported32.map",
+        },
+        lib64: {
+            version_script: "exported64.map",
+        },
+    },
+    include_dirs: ["bionic/libc"],
+
+    sanitize: {
+        never: true,
+    },
+    native_coverage: false,
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-fno-stack-protector",
+    ],
+}
+
+// ==============================================================
+// Unit Tests
+// ==============================================================
+cc_test {
+    name: "malloc_hooks_unit_tests",
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+
+    srcs: [
+        "tests/malloc_hooks_tests.cpp",
+    ],
+
+    whole_static_libs: ["libc_malloc_hooks"],
+
+    shared_libs: ["libbase"],
+
+    local_include_dirs: ["tests"],
+    include_dirs: ["bionic/libc", "bionic"],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/libc/malloc_hooks/README.md b/libc/malloc_hooks/README.md
new file mode 100644
index 0000000..85b2769
--- /dev/null
+++ b/libc/malloc_hooks/README.md
@@ -0,0 +1,118 @@
+Malloc Hooks
+============
+
+Malloc hooks allows a program to intercept all allocation/free calls that
+happen during execution. It is only available in Android P and newer versions
+of the OS.
+
+There are two ways to enable these hooks, set a special system
+property, or set a special environment variable and run your app/program.
+
+When malloc hooks is enabled, it works by adding a shim layer that replaces
+the normal allocation calls. The replaced calls are:
+
+* `malloc`
+* `free`
+* `calloc`
+* `realloc`
+* `posix_memalign`
+* `memalign`
+* `aligned_alloc`
+* `malloc_usable_size`
+
+On 32 bit systems, these two deprecated functions are also replaced:
+
+* `pvalloc`
+* `valloc`
+
+These four hooks are defined in malloc.h:
+
+    void* (*volatile __malloc_hook)(size_t, const void*);
+    void* (*volatile __realloc_hook)(void*, size_t, const void*);
+    void (*volatile __free_hook)(void*, const void*);
+    void* (*volatile __memalign_hook)(size_t, size_t, const void*);
+
+When malloc is called and \_\_malloc\_hook has been set, then the hook
+function is called instead.
+
+When realloc is called and \_\_realloc\_hook has been set, then the hook
+function is called instead.
+
+When free is called and \_\_free\_hook has been set, then the hook
+function is called instead.
+
+When memalign is called and \_\_memalign\_hook has been set, then the hook
+function is called instead.
+
+For posix\_memalign, if \_\_memalign\_hook has been set, then the hook is
+called, but only if alignment is a power of 2.
+
+For aligned\_alloc, if \_\_memalign\_hook has been set, then the hook is
+called, but only if alignment is a power of 2.
+
+For calloc, if \_\_malloc\_hook has been set, then the hook function is
+called, then the allocated memory is set to zero.
+
+For the two deprecated functions pvalloc and valloc, if \_\_memalign\_hook
+has been set, then the hook is called with an appropriate alignment value.
+
+There is no hook for malloc\_usable\_size as of now.
+
+These hooks can be set at any time, but there is no thread safety, so
+the caller must guarantee that it does not depend on allocations/frees
+occurring at the same time.
+
+Implementation Details
+======================
+When malloc hooks is enabled, then the hook pointers are set to
+the current default allocation functions. It is expected that if an
+app does intercept the allocation/free calls, it will eventually call
+the original hook function to do allocations. If the app does not do this,
+it runs the risk of crashing whenever a malloc\_usable\_size call is made.
+
+Example Implementation
+======================
+Below is a simple implementation intercepting only malloc/calloc calls.
+
+    void* new_malloc_hook(size_t bytes, const char* arg) {
+      return orig_malloc_hook(bytes, arg);
+    }
+
+    void orig_malloc_hook = __malloc_hook;
+    __malloc_hook = new_malloc_hook;
+
+Enabling Examples
+=================
+
+### For platform developers
+
+Enable the hooks for all processes:
+
+    adb shell stop
+    adb shell setprop libc.debug.malloc.hooks 1
+    adb shell start
+
+Enable malloc debug using an environment variable:
+
+    adb shell
+    # export LIBC_HOOK_ENABLE=1
+    # ls
+
+Any process spawned from this shell will run with malloc hooks enabled.
+
+### For app developers
+
+Enable malloc hooks for a specific program/application:
+
+    adb shell setprop wrap.<APP> '"LIBC_HOOKS_ENABLE=1"'
+
+For example, to enable malloc hooks for the google search box:
+
+    adb shell setprop wrap.com.google.android.googlequicksearchbox '"LIBC_HOOKS_ENABLE=1 logwrapper"'
+    adb shell am force-stop com.google.android.googlequicksearchbox
+
+NOTE: On pre-O versions of the Android OS, property names had a length limit
+of 32. This meant that to create a wrap property with the name of the app, it
+was necessary to truncate the name to fit. On O, property names can be
+an order of magnitude larger, so there should be no need to truncate the name
+at all.
diff --git a/libc/malloc_hooks/exported32.map b/libc/malloc_hooks/exported32.map
new file mode 100644
index 0000000..2cf5b8c
--- /dev/null
+++ b/libc/malloc_hooks/exported32.map
@@ -0,0 +1,26 @@
+LIBC_MALLOC_HOOKS {
+  global:
+    hooks_aligned_alloc;
+    hooks_calloc;
+    hooks_finalize;
+    hooks_free;
+    hooks_free_malloc_leak_info;
+    hooks_get_malloc_leak_info;
+    hooks_initialize;
+    hooks_iterate;
+    hooks_mallinfo;
+    hooks_malloc;
+    hooks_malloc_backtrace;
+    hooks_malloc_disable;
+    hooks_malloc_enable;
+    hooks_malloc_usable_size;
+    hooks_mallopt;
+    hooks_memalign;
+    hooks_posix_memalign;
+    hooks_pvalloc;
+    hooks_realloc;
+    hooks_valloc;
+
+  local:
+    *;
+};
diff --git a/libc/malloc_hooks/exported64.map b/libc/malloc_hooks/exported64.map
new file mode 100644
index 0000000..5ebcf9f
--- /dev/null
+++ b/libc/malloc_hooks/exported64.map
@@ -0,0 +1,24 @@
+LIBC_MALLOC_HOOKS {
+  global:
+    hooks_aligned_alloc;
+    hooks_calloc;
+    hooks_finalize;
+    hooks_free;
+    hooks_free_malloc_leak_info;
+    hooks_get_malloc_leak_info;
+    hooks_initialize;
+    hooks_iterate;
+    hooks_mallinfo;
+    hooks_malloc;
+    hooks_malloc_backtrace;
+    hooks_malloc_disable;
+    hooks_malloc_enable;
+    hooks_malloc_usable_size;
+    hooks_mallopt;
+    hooks_memalign;
+    hooks_posix_memalign;
+    hooks_realloc;
+
+  local:
+    *;
+};
diff --git a/libc/malloc_hooks/malloc_hooks.cpp b/libc/malloc_hooks/malloc_hooks.cpp
new file mode 100644
index 0000000..662520c
--- /dev/null
+++ b/libc/malloc_hooks/malloc_hooks.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2018 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 <errno.h>
+#include <malloc.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+#include <private/bionic_malloc_dispatch.h>
+
+// ------------------------------------------------------------------------
+// Global Data
+// ------------------------------------------------------------------------
+const MallocDispatch* g_dispatch;
+// ------------------------------------------------------------------------
+
+// ------------------------------------------------------------------------
+// Use C style prototypes for all exported functions. This makes it easy
+// to do dlsym lookups during libc initialization when hooks are enabled.
+// ------------------------------------------------------------------------
+__BEGIN_DECLS
+
+bool hooks_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child,
+    const char* options);
+void hooks_finalize();
+void hooks_get_malloc_leak_info(
+    uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory,
+    size_t* backtrace_size);
+ssize_t hooks_malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count);
+void hooks_free_malloc_leak_info(uint8_t* info);
+size_t hooks_malloc_usable_size(void* pointer);
+void* hooks_malloc(size_t size);
+void hooks_free(void* pointer);
+void* hooks_memalign(size_t alignment, size_t bytes);
+void* hooks_aligned_alloc(size_t alignment, size_t bytes);
+void* hooks_realloc(void* pointer, size_t bytes);
+void* hooks_calloc(size_t nmemb, size_t bytes);
+struct mallinfo hooks_mallinfo();
+int hooks_mallopt(int param, int value);
+int hooks_posix_memalign(void** memptr, size_t alignment, size_t size);
+int hooks_iterate(uintptr_t base, size_t size,
+    void (*callback)(uintptr_t base, size_t size, void* arg), void* arg);
+void hooks_malloc_disable();
+void hooks_malloc_enable();
+
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+void* hooks_pvalloc(size_t bytes);
+void* hooks_valloc(size_t size);
+#endif
+
+static void* default_malloc_hook(size_t bytes, const void*) {
+  return g_dispatch->malloc(bytes);
+}
+
+static void* default_realloc_hook(void* pointer, size_t bytes, const void*) {
+  return g_dispatch->realloc(pointer, bytes);
+}
+
+static void default_free_hook(void* pointer, const void*) {
+  g_dispatch->free(pointer);
+}
+
+static void* default_memalign_hook(size_t alignment, size_t bytes, const void*) {
+  return g_dispatch->memalign(alignment, bytes);
+}
+
+__END_DECLS
+// ------------------------------------------------------------------------
+
+bool hooks_initialize(const MallocDispatch* malloc_dispatch, int*, const char*) {
+  g_dispatch = malloc_dispatch;
+  __malloc_hook = default_malloc_hook;
+  __realloc_hook = default_realloc_hook;
+  __free_hook = default_free_hook;
+  __memalign_hook = default_memalign_hook;
+  return true;
+}
+
+void hooks_finalize() {
+}
+
+void hooks_get_malloc_leak_info(uint8_t** info, size_t* overall_size,
+    size_t* info_size, size_t* total_memory, size_t* backtrace_size) {
+  *info = nullptr;
+  *overall_size = 0;
+  *info_size = 0;
+  *total_memory = 0;
+  *backtrace_size = 0;
+}
+
+void hooks_free_malloc_leak_info(uint8_t*) {
+}
+
+size_t hooks_malloc_usable_size(void* pointer) {
+  return g_dispatch->malloc_usable_size(pointer);
+}
+
+void* hooks_malloc(size_t size) {
+  if (__malloc_hook != nullptr && __malloc_hook != default_malloc_hook) {
+    return __malloc_hook(size, __builtin_return_address(0));
+  }
+  return g_dispatch->malloc(size);
+}
+
+void hooks_free(void* pointer) {
+  if (__free_hook != nullptr && __free_hook != default_free_hook) {
+    return __free_hook(pointer, __builtin_return_address(0));
+  }
+  return g_dispatch->free(pointer);
+}
+
+void* hooks_memalign(size_t alignment, size_t bytes) {
+  if (__memalign_hook != nullptr && __memalign_hook != default_memalign_hook) {
+    return __memalign_hook(alignment, bytes, __builtin_return_address(0));
+  }
+  return g_dispatch->memalign(alignment, bytes);
+}
+
+void* hooks_realloc(void* pointer, size_t bytes) {
+  if (__realloc_hook != nullptr && __realloc_hook != default_realloc_hook) {
+    return __realloc_hook(pointer, bytes, __builtin_return_address(0));
+  }
+  return g_dispatch->realloc(pointer, bytes);
+}
+
+void* hooks_calloc(size_t nmemb, size_t bytes) {
+  if (__malloc_hook != nullptr && __malloc_hook != default_malloc_hook) {
+    size_t size;
+    if (__builtin_mul_overflow(nmemb, bytes, &size)) {
+      return nullptr;
+    }
+    void* ptr = __malloc_hook(size, __builtin_return_address(0));
+    if (ptr != nullptr) {
+      memset(ptr, 0, size);
+    }
+    return ptr;
+  }
+  return g_dispatch->calloc(nmemb, bytes);
+}
+
+struct mallinfo hooks_mallinfo() {
+  return g_dispatch->mallinfo();
+}
+
+int hooks_mallopt(int param, int value) {
+  return g_dispatch->mallopt(param, value);
+}
+
+void* hooks_aligned_alloc(size_t alignment, size_t size) {
+  if (__memalign_hook != nullptr && __memalign_hook != default_memalign_hook) {
+    if (!powerof2(alignment)) {
+      errno = EINVAL;
+      return nullptr;
+    }
+    void* ptr = __memalign_hook(alignment, size, __builtin_return_address(0));
+    if (ptr == nullptr) {
+      errno = ENOMEM;
+    }
+    return ptr;
+  }
+  return g_dispatch->aligned_alloc(alignment, size);
+}
+
+int hooks_posix_memalign(void** memptr, size_t alignment, size_t size) {
+  if (__memalign_hook != nullptr && __memalign_hook != default_memalign_hook) {
+    if (!powerof2(alignment)) {
+      return EINVAL;
+    }
+    *memptr = __memalign_hook(alignment, size, __builtin_return_address(0));
+    if (*memptr == nullptr) {
+      return ENOMEM;
+    }
+    return 0;
+  }
+  return g_dispatch->posix_memalign(memptr, alignment, size);
+}
+
+int hooks_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*) {
+  return 0;
+}
+
+void hooks_malloc_disable() {
+}
+
+void hooks_malloc_enable() {
+}
+
+ssize_t hooks_malloc_backtrace(void*, uintptr_t*, size_t) {
+  return 0;
+}
+
+#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
+void* hooks_pvalloc(size_t bytes) {
+  size_t pagesize = getpagesize();
+  size_t size = __BIONIC_ALIGN(bytes, pagesize);
+  if (size < bytes) {
+    // Overflow
+    errno = ENOMEM;
+    return nullptr;
+  }
+  return hooks_memalign(pagesize, size);
+}
+
+void* hooks_valloc(size_t size) {
+  return hooks_memalign(getpagesize(), size);
+}
+#endif
diff --git a/libc/malloc_hooks/tests/malloc_hooks_tests.cpp b/libc/malloc_hooks/tests/malloc_hooks_tests.cpp
new file mode 100644
index 0000000..0d23a6a
--- /dev/null
+++ b/libc/malloc_hooks/tests/malloc_hooks_tests.cpp
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2018 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 <fcntl.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <private/bionic_malloc_dispatch.h>
+#include <tests/utils.h>
+
+__BEGIN_DECLS
+
+void get_malloc_leak_info(uint8_t**, size_t*, size_t*, size_t*, size_t*);
+void free_malloc_leak_info(uint8_t*);
+int malloc_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*);
+void malloc_enable();
+void malloc_disable();
+ssize_t malloc_backtrace(void*, uintptr_t*, size_t);
+
+__END_DECLS
+
+class MallocHooksTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    ASSERT_EQ(0, setenv("LIBC_HOOKS_ENABLE", "1", true));
+    initialized_ = false;
+  }
+
+  void TearDown() override {
+    if (initialized_) {
+      Reset();
+    }
+    ASSERT_EQ(0, unsetenv("LIBC_HOOKS_ENABLE"));
+  }
+
+  void Init() {
+    initialized_ = true;
+    malloc_hook_called_ = false;
+    free_hook_called_ = false;
+    realloc_hook_called_ = false;
+    memalign_hook_called_ = false;
+
+    void_arg_ = nullptr;
+
+    orig_malloc_hook_ = __malloc_hook;
+    orig_free_hook_ = __free_hook;
+    orig_realloc_hook_ = __realloc_hook;
+    orig_memalign_hook_ = __memalign_hook;
+  }
+
+  void Reset() {
+    __malloc_hook = orig_malloc_hook_;
+    __free_hook = orig_free_hook_;
+    __realloc_hook = orig_realloc_hook_;
+    __memalign_hook = orig_memalign_hook_;
+  }
+
+  void Exec(std::vector<const char*> args);
+  void RunTest(std::string test_name);
+
+ public:
+  bool initialized_;
+
+  int fd_;
+  std::string raw_output_;
+  pid_t pid_;
+
+  static bool malloc_hook_called_;
+  static bool free_hook_called_;
+  static bool realloc_hook_called_;
+  static bool memalign_hook_called_;
+  static const void* void_arg_;
+
+  static void* (*orig_malloc_hook_)(size_t, const void*);
+  static void (*orig_free_hook_)(void*, const void*);
+  static void* (*orig_realloc_hook_)(void*, size_t, const void*);
+  static void* (*orig_memalign_hook_)(size_t, size_t, const void*);
+
+  static void* test_malloc_hook(size_t, const void*);
+  static void* test_realloc_hook(void* ptr, size_t, const void*);
+  static void* test_memalign_hook(size_t, size_t, const void*);
+  static void test_free_hook(void*, const void*);
+};
+
+bool MallocHooksTest::malloc_hook_called_;
+bool MallocHooksTest::free_hook_called_;
+bool MallocHooksTest::realloc_hook_called_;
+bool MallocHooksTest::memalign_hook_called_;
+const void* MallocHooksTest::void_arg_;
+
+void* (*MallocHooksTest::orig_malloc_hook_)(size_t, const void*);
+void (*MallocHooksTest::orig_free_hook_)(void*, const void*);
+void* (*MallocHooksTest::orig_realloc_hook_)(void*, size_t, const void*);
+void* (*MallocHooksTest::orig_memalign_hook_)(size_t, size_t, const void*);
+
+static void GetExe(std::string* exe_name) {
+  char path[PATH_MAX];
+  ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path));
+  ASSERT_TRUE(path_len >= 0);
+  *exe_name = std::string(path, path_len);
+}
+
+void MallocHooksTest::RunTest(std::string test_name) {
+  std::vector<const char*> args;
+  args.push_back("--gtest_also_run_disabled_tests");
+  std::string filter_arg("--gtest_filter=" + test_name);
+  args.push_back(filter_arg.c_str());
+
+  ExecTestHelper test;
+  test.Run(
+      [&]() {
+        std::string exe_name;
+        GetExe(&exe_name);
+        args.insert(args.begin(), exe_name.c_str());
+        args.push_back(nullptr);
+        execv(args[0], reinterpret_cast<char* const*>(const_cast<char**>(args.data())));
+        exit(1);
+      },
+      0, nullptr);
+}
+
+void* MallocHooksTest::test_malloc_hook(size_t size, const void* arg) {
+  malloc_hook_called_ = true;
+  void_arg_ = arg;
+  return orig_malloc_hook_(size, arg);
+}
+
+void* MallocHooksTest::test_realloc_hook(void* ptr, size_t size, const void* arg) {
+  realloc_hook_called_ = true;
+  void_arg_ = arg;
+  return orig_realloc_hook_(ptr, size, arg);
+}
+
+void* MallocHooksTest::test_memalign_hook(size_t alignment, size_t size, const void* arg) {
+  memalign_hook_called_ = true;
+  void_arg_ = arg;
+  return orig_memalign_hook_(alignment, size, arg);
+}
+
+void MallocHooksTest::test_free_hook(void* ptr, const void* arg) {
+  free_hook_called_ = true;
+  void_arg_ = arg;
+  return orig_free_hook_(ptr, arg);
+}
+
+TEST_F(MallocHooksTest, other_malloc_functions) {
+  RunTest("*.DISABLED_other_malloc_functions");
+}
+
+// Call other intercepted functions to make sure there are no crashes.
+TEST_F(MallocHooksTest, DISABLED_other_malloc_functions) {
+  struct mallinfo info = mallinfo();
+  EXPECT_NE(0U, info.uordblks);
+
+  EXPECT_EQ(0, mallopt(-1000, -1000));
+
+  void* ptr = malloc(1024);
+  EXPECT_LE(1024U, malloc_usable_size(ptr));
+  free(ptr);
+}
+
+TEST_F(MallocHooksTest, extended_functions) {
+  RunTest("*.DISABLED_extended_functions");
+}
+
+TEST_F(MallocHooksTest, DISABLED_extended_functions) {
+  uint8_t* info = nullptr;
+  size_t overall_size = 100;
+  size_t info_size = 200;
+  size_t total_memory = 300;
+  size_t backtrace_size = 400;
+  get_malloc_leak_info(&info, &overall_size, &info_size, &total_memory, &backtrace_size);
+  EXPECT_EQ(nullptr, info);
+  EXPECT_EQ(0U, overall_size);
+  EXPECT_EQ(0U, info_size);
+  EXPECT_EQ(0U, total_memory);
+  EXPECT_EQ(0U, backtrace_size);
+
+  free_malloc_leak_info(info);
+
+  malloc_enable();
+  malloc_disable();
+
+  EXPECT_EQ(0, malloc_iterate(0, 0, nullptr, nullptr));
+
+  // Malloc hooks doesn't support any backtracing.
+  EXPECT_EQ(0, malloc_backtrace(nullptr, nullptr, 10));
+}
+
+TEST_F(MallocHooksTest, malloc_hook) {
+  RunTest("*.DISABLED_malloc_hook");
+}
+
+TEST_F(MallocHooksTest, DISABLED_malloc_hook) {
+  Init();
+  ASSERT_TRUE(__malloc_hook != nullptr);
+  __malloc_hook = test_malloc_hook;
+
+  void* ptr = malloc(1024);
+  ASSERT_TRUE(ptr != nullptr);
+  write(0, ptr, 0);
+  free(ptr);
+
+  EXPECT_TRUE(malloc_hook_called_) << "The malloc hook was not called.";
+  EXPECT_TRUE(void_arg_ != nullptr) << "The malloc hook was called with a nullptr.";
+}
+
+TEST_F(MallocHooksTest, free_hook) {
+  RunTest("*.DISABLED_free_hook");
+}
+
+TEST_F(MallocHooksTest, DISABLED_free_hook) {
+  Init();
+  ASSERT_TRUE(__free_hook != nullptr);
+  __free_hook = test_free_hook;
+
+  void* ptr = malloc(1024);
+  ASSERT_TRUE(ptr != nullptr);
+  free(ptr);
+  write(0, ptr, 0);
+
+  EXPECT_TRUE(free_hook_called_) << "The free hook was not called.";
+  EXPECT_TRUE(void_arg_ != nullptr) << "The free hook was called with a nullptr.";
+}
+
+TEST_F(MallocHooksTest, realloc_hook) {
+  RunTest("*.DISABLED_realloc_hook");
+}
+
+TEST_F(MallocHooksTest, DISABLED_realloc_hook) {
+  Init();
+  ASSERT_TRUE(__realloc_hook != nullptr);
+  __realloc_hook = test_realloc_hook;
+
+  void* ptr = malloc(1024);
+  ASSERT_TRUE(ptr != nullptr);
+  ptr = realloc(ptr, 2048);
+  free(ptr);
+  write(0, ptr, 0);
+
+  EXPECT_TRUE(realloc_hook_called_) << "The realloc hook was not called.";
+  EXPECT_TRUE(void_arg_ != nullptr) << "The realloc hook was called with a nullptr.";
+}
+
+TEST_F(MallocHooksTest, memalign_hook) {
+  RunTest("*.DISABLED_memalign_hook");
+}
+
+TEST_F(MallocHooksTest, DISABLED_memalign_hook) {
+  Init();
+  ASSERT_TRUE(__memalign_hook != nullptr);
+  __memalign_hook = test_memalign_hook;
+
+  void* ptr = memalign(32, 1024);
+  ASSERT_TRUE(ptr != nullptr);
+  free(ptr);
+  write(0, ptr, 0);
+
+  EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called.";
+  EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
+}
+
+TEST_F(MallocHooksTest, posix_memalign_hook) {
+  RunTest("*.DISABLED_posix_memalign_hook");
+}
+
+TEST_F(MallocHooksTest, DISABLED_posix_memalign_hook) {
+  Init();
+  ASSERT_TRUE(__memalign_hook != nullptr);
+  __memalign_hook = test_memalign_hook;
+
+  void* ptr;
+  ASSERT_EQ(0, posix_memalign(&ptr, 32, 1024));
+  ASSERT_TRUE(ptr != nullptr);
+  free(ptr);
+  write(0, ptr, 0);
+
+  EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called when running posix_memalign.";
+  EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
+}
+
+TEST_F(MallocHooksTest, posix_memalign_hook_error) {
+  RunTest("*.DISABLED_posix_memalign_hook_error");
+}
+
+TEST_F(MallocHooksTest, DISABLED_posix_memalign_hook_error) {
+  Init();
+  ASSERT_TRUE(__memalign_hook != nullptr);
+  __memalign_hook = test_memalign_hook;
+
+  void* ptr;
+  ASSERT_EQ(EINVAL, posix_memalign(&ptr, 11, 1024));
+  write(0, ptr, 0);
+
+  EXPECT_FALSE(memalign_hook_called_)
+      << "The memalign hook was called when running posix_memalign with an error.";
+  EXPECT_FALSE(void_arg_ != nullptr)
+      << "The memalign hook was called with a nullptr with an error.";
+}
+
+TEST_F(MallocHooksTest, aligned_alloc_hook) {
+  RunTest("*.DISABLED_aligned_alloc_hook");
+}
+
+TEST_F(MallocHooksTest, DISABLED_aligned_alloc_hook) {
+  Init();
+  ASSERT_TRUE(__memalign_hook != nullptr);
+  __memalign_hook = test_memalign_hook;
+
+  void* ptr = aligned_alloc(32, 1024);
+  ASSERT_TRUE(ptr != nullptr);
+  free(ptr);
+  write(0, ptr, 0);
+
+  EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called when running aligned_alloc.";
+  EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
+}
+
+TEST_F(MallocHooksTest, aligned_alloc_hook_error) {
+  RunTest("*.DISABLED_aligned_alloc_hook_error");
+}
+
+TEST_F(MallocHooksTest, DISABLED_aligned_alloc_hook_error) {
+  Init();
+  ASSERT_TRUE(__memalign_hook != nullptr);
+  __memalign_hook = test_memalign_hook;
+
+  void* ptr = aligned_alloc(11, 1024);
+  ASSERT_TRUE(ptr == nullptr);
+  EXPECT_EQ(EINVAL, errno);
+  write(0, ptr, 0);
+
+  EXPECT_FALSE(memalign_hook_called_)
+      << "The memalign hook was called when running aligned_alloc with an error.";
+  EXPECT_FALSE(void_arg_ != nullptr)
+      << "The memalign hook was called with a nullptr with an error.";
+}
+
+#if !defined(__LP64__)
+TEST_F(MallocHooksTest, pvalloc_hook) {
+  RunTest("*.DISABLED_pvalloc_hook");
+}
+
+extern "C" void* pvalloc(size_t);
+
+TEST_F(MallocHooksTest, DISABLED_pvalloc_hook) {
+  Init();
+  ASSERT_TRUE(__memalign_hook != nullptr);
+  __memalign_hook = test_memalign_hook;
+
+  void* ptr = pvalloc(1024);
+  ASSERT_TRUE(ptr != nullptr);
+  write(0, ptr, 0);
+  free(ptr);
+
+  EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called for pvalloc.";
+  EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
+}
+
+TEST_F(MallocHooksTest, valloc_hook) {
+  RunTest("*.DISABLED_valloc_hook");
+}
+
+extern "C" void* valloc(size_t);
+
+TEST_F(MallocHooksTest, DISABLED_valloc_hook) {
+  Init();
+  ASSERT_TRUE(__memalign_hook != nullptr);
+  __memalign_hook = test_memalign_hook;
+
+  void* ptr = valloc(1024);
+  ASSERT_TRUE(ptr != nullptr);
+  write(0, ptr, 0);
+  free(ptr);
+
+  EXPECT_TRUE(memalign_hook_called_) << "The memalign hook was not called for valloc.";
+  EXPECT_TRUE(void_arg_ != nullptr) << "The memalign hook was called with a nullptr.";
+}
+#endif
diff --git a/libc/seccomp/include/seccomp_policy.h b/libc/seccomp/include/seccomp_policy.h
index add17b9..49280f4 100644
--- a/libc/seccomp/include/seccomp_policy.h
+++ b/libc/seccomp/include/seccomp_policy.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SECCOMP_POLICY_H
-#define SECCOMP_POLICY_H
+#pragma once
 
 #include <stddef.h>
 #include <linux/filter.h>
@@ -23,5 +22,3 @@
 bool set_app_seccomp_filter();
 bool set_system_seccomp_filter();
 bool set_global_seccomp_filter();
-
-#endif
diff --git a/libc/seccomp/seccomp_bpfs.h b/libc/seccomp/seccomp_bpfs.h
index 8728c36..797dfc5 100644
--- a/libc/seccomp/seccomp_bpfs.h
+++ b/libc/seccomp/seccomp_bpfs.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef SECCOMP_BPFS_H
-#define SECCOMP_BPFS_H
+#pragma once
 
 #include <stddef.h>
 #include <linux/seccomp.h>
@@ -61,5 +60,3 @@
 extern const size_t mips64_system_filter_size;
 extern const struct sock_filter mips64_global_filter[];
 extern const size_t mips64_global_filter_size;
-
-#endif
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index a31d7b9..11b136d 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -32,8 +32,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __BIONIC_STDIO_LOCAL_H__
-#define __BIONIC_STDIO_LOCAL_H__
+#pragma once
 
 #include <pthread.h>
 #include <stdbool.h>
@@ -278,5 +277,3 @@
 char* __ldtoa(long double*, int, int, int*, int*, char**);
 
 __END_DECLS
-
-#endif
diff --git a/libc/stdio/wcio.h b/libc/stdio/wcio.h
index 3c4f7a4..047eb77 100644
--- a/libc/stdio/wcio.h
+++ b/libc/stdio/wcio.h
@@ -29,8 +29,7 @@
  * $Citrus$
  */
 
-#ifndef _WCIO_H_
-#define _WCIO_H_
+#pragma once
 
 #include <sys/cdefs.h>
 
@@ -80,5 +79,3 @@
 } while (0)
 
 __END_DECLS
-
-#endif /*_WCIO_H_*/
diff --git a/libc/system_properties/include/system_properties/context_node.h b/libc/system_properties/include/system_properties/context_node.h
index 6a3bbcd..35d0e92 100644
--- a/libc/system_properties/include/system_properties/context_node.h
+++ b/libc/system_properties/include/system_properties/context_node.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef SYSTEM_PROPERTIES_CONTEXT_NODE_H
-#define SYSTEM_PROPERTIES_CONTEXT_NODE_H
+#pragma once
 
 #include "private/bionic_lock.h"
 
@@ -66,5 +65,3 @@
   bool no_access_;
   const char* filename_;
 };
-
-#endif
diff --git a/libc/system_properties/include/system_properties/contexts.h b/libc/system_properties/include/system_properties/contexts.h
index 8f154ed..670f808 100644
--- a/libc/system_properties/include/system_properties/contexts.h
+++ b/libc/system_properties/include/system_properties/contexts.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef SYSTEM_PROPERTIES_CONTEXTS_H
-#define SYSTEM_PROPERTIES_CONTEXTS_H
+#pragma once
 
 #include "prop_area.h"
 #include "prop_info.h"
@@ -44,5 +43,3 @@
   virtual void ResetAccess() = 0;
   virtual void FreeAndUnmap() = 0;
 };
-
-#endif
diff --git a/libc/system_properties/include/system_properties/contexts_pre_split.h b/libc/system_properties/include/system_properties/contexts_pre_split.h
index 14b00f1..6e695e9 100644
--- a/libc/system_properties/include/system_properties/contexts_pre_split.h
+++ b/libc/system_properties/include/system_properties/contexts_pre_split.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef SYSTEM_PROPERTIES_CONTEXTS_PRE_SPLIT_H
-#define SYSTEM_PROPERTIES_CONTEXTS_PRE_SPLIT_H
+#pragma once
 
 #include "contexts.h"
 #include "prop_area.h"
@@ -68,5 +67,3 @@
  private:
   prop_area* pre_split_prop_area_ = nullptr;
 };
-
-#endif
diff --git a/libc/system_properties/include/system_properties/contexts_serialized.h b/libc/system_properties/include/system_properties/contexts_serialized.h
index 010730a..93d6ac1 100644
--- a/libc/system_properties/include/system_properties/contexts_serialized.h
+++ b/libc/system_properties/include/system_properties/contexts_serialized.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef SYSTEM_PROPERTIES_CONTEXTS_SERIALIZED_H
-#define SYSTEM_PROPERTIES_CONTEXTS_SERIALIZED_H
+#pragma once
 
 #include <property_info_parser/property_info_parser.h>
 
@@ -60,5 +59,3 @@
   size_t context_nodes_mmap_size_ = 0;
   prop_area* serial_prop_area_ = nullptr;
 };
-
-#endif
diff --git a/libc/system_properties/include/system_properties/contexts_split.h b/libc/system_properties/include/system_properties/contexts_split.h
index 06c405a..acb18e3 100644
--- a/libc/system_properties/include/system_properties/contexts_split.h
+++ b/libc/system_properties/include/system_properties/contexts_split.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef SYSTEM_PROPERTIES_CONTEXTS_SPLIT_H
-#define SYSTEM_PROPERTIES_CONTEXTS_SPLIT_H
+#pragma once
 
 #include "contexts.h"
 
@@ -58,5 +57,3 @@
   prop_area* serial_prop_area_ = nullptr;
   const char* filename_ = nullptr;
 };
-
-#endif
diff --git a/libc/system_properties/include/system_properties/prop_area.h b/libc/system_properties/include/system_properties/prop_area.h
index a7d5d22..2c25337 100644
--- a/libc/system_properties/include/system_properties/prop_area.h
+++ b/libc/system_properties/include/system_properties/prop_area.h
@@ -26,6 +26,8 @@
  * SUCH DAMAGE.
  */
 
+#pragma once
+
 #include <stdatomic.h>
 #include <stdint.h>
 #include <string.h>
@@ -35,9 +37,6 @@
 
 #include "prop_info.h"
 
-#ifndef SYSTEM_PROPERTIES_PROP_AREA_H
-#define SYSTEM_PROPERTIES_PROP_AREA_H
-
 // Properties are stored in a hybrid trie/binary tree structure.
 // Each property's name is delimited at '.' characters, and the tokens are put
 // into a trie structure.  Siblings at each level of the trie are stored in a
@@ -161,5 +160,3 @@
 
   DISALLOW_COPY_AND_ASSIGN(prop_area);
 };
-
-#endif
diff --git a/libc/system_properties/include/system_properties/prop_info.h b/libc/system_properties/include/system_properties/prop_info.h
index 99bcaaf..a127550 100644
--- a/libc/system_properties/include/system_properties/prop_info.h
+++ b/libc/system_properties/include/system_properties/prop_info.h
@@ -26,15 +26,14 @@
  * SUCH DAMAGE.
  */
 
+#pragma once
+
 #include <stdatomic.h>
 #include <stdint.h>
 #include <sys/system_properties.h>
 
 #include "private/bionic_macros.h"
 
-#ifndef SYSTEM_PROPERTIES_PROP_INFO_H
-#define SYSTEM_PROPERTIES_PROP_INFO_H
-
 // The C11 standard doesn't allow atomic loads from const fields,
 // though C++11 does.  Fudge it until standards get straightened out.
 static inline uint_least32_t load_const_atomic(const atomic_uint_least32_t* s, memory_order mo) {
@@ -88,5 +87,3 @@
 };
 
 static_assert(sizeof(prop_info) == 96, "sizeof struct prop_info must be 96 bytes");
-
-#endif
diff --git a/libc/system_properties/include/system_properties/system_properties.h b/libc/system_properties/include/system_properties/system_properties.h
index 83ac00c..37fe6c0 100644
--- a/libc/system_properties/include/system_properties/system_properties.h
+++ b/libc/system_properties/include/system_properties/system_properties.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef SYSTEM_PROPERTIES_SYSTEM_PROPERTIES_H
-#define SYSTEM_PROPERTIES_SYSTEM_PROPERTIES_H
+#pragma once
 
 #include <stdint.h>
 #include <sys/system_properties.h>
@@ -92,5 +91,3 @@
   bool initialized_;
   char property_filename_[PROP_FILENAME_MAX];
 };
-
-#endif
diff --git a/libm/fpmath.h b/libm/fpmath.h
index 80420e5..854ba11 100644
--- a/libm/fpmath.h
+++ b/libm/fpmath.h
@@ -33,8 +33,7 @@
 // - android uses 128 bits long doubles for LP64, so the structure and macros
 //   were reworked for the quad precision ieee representation.
 
-#ifndef _FPMATH_
-#define _FPMATH_
+#pragma once
 
 #include <endian.h>
 
@@ -92,5 +91,3 @@
 } while(0)
 
 #endif // __LP64__
-
-#endif // _FPMATH_
diff --git a/libm/freebsd-compat.h b/libm/freebsd-compat.h
index ee41e45..0bcc40d 100644
--- a/libm/freebsd-compat.h
+++ b/libm/freebsd-compat.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef _BIONIC_LIBM_FREEBSD_COMPAT_H_included
-#define _BIONIC_LIBM_FREEBSD_COMPAT_H_included
+#pragma once
 
 #include <float.h>
 
@@ -38,5 +37,3 @@
 
 // Similarly rename _scan_nan.
 #define _scan_nan __libm_scan_nan
-
-#endif
diff --git a/linker/linked_list.h b/linker/linked_list.h
index ed2b150..048ea4d 100644
--- a/linker/linked_list.h
+++ b/linker/linked_list.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __LINKED_LIST_H
-#define __LINKED_LIST_H
+#pragma once
 
 #include "private/bionic_macros.h"
 
@@ -259,5 +258,3 @@
   LinkedListEntry<T>* tail_;
   DISALLOW_COPY_AND_ASSIGN(LinkedList);
 };
-
-#endif // __LINKED_LIST_H
diff --git a/linker/linker.h b/linker/linker.h
index 29d40fa..260c89d 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LINKER_H_
-#define _LINKER_H_
+#pragma once
 
 #include <dlfcn.h>
 #include <android/dlext.h>
@@ -187,5 +186,3 @@
 
 void increment_dso_handle_reference_counter(void* dso_handle);
 void decrement_dso_handle_reference_counter(void* dso_handle);
-
-#endif
diff --git a/linker/linker_allocator.h b/linker/linker_allocator.h
index 7fc6cbf..82e4ef4 100644
--- a/linker/linker_allocator.h
+++ b/linker/linker_allocator.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __LINKER_ALLOCATOR_H
-#define __LINKER_ALLOCATOR_H
+#pragma once
 
 #include <errno.h>
 #include <stdlib.h>
@@ -152,6 +151,3 @@
   LinkerSmallObjectAllocator* allocators_;
   uint8_t allocators_buf_[sizeof(LinkerSmallObjectAllocator)*kSmallObjectAllocatorsCount];
 };
-
-
-#endif  /* __LINKER_ALLOCATOR_H */
diff --git a/linker/linker_block_allocator.h b/linker/linker_block_allocator.h
index eba1db2..b501659 100644
--- a/linker/linker_block_allocator.h
+++ b/linker/linker_block_allocator.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __LINKER_BLOCK_ALLOCATOR_H
-#define __LINKER_BLOCK_ALLOCATOR_H
+#pragma once
 
 #include <stdlib.h>
 #include <limits.h>
@@ -89,5 +88,3 @@
   LinkerBlockAllocator block_allocator_;
   DISALLOW_COPY_AND_ASSIGN(LinkerTypeAllocator);
 };
-
-#endif // __LINKER_BLOCK_ALLOCATOR_H
diff --git a/linker/linker_cfi.h b/linker/linker_cfi.h
index e54554f..f3300d6 100644
--- a/linker/linker_cfi.h
+++ b/linker/linker_cfi.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LINKER_CFI_H_
-#define _LINKER_CFI_H_
+#pragma once
 
 #include "linker.h"
 #include "linker_debug.h"
@@ -103,5 +102,3 @@
 };
 
 CFIShadowWriter* get_cfi_shadow();
-
-#endif // _LINKER_CFI_H_
diff --git a/linker/linker_common_types.h b/linker/linker_common_types.h
index 6afd950..ffa4066 100644
--- a/linker/linker_common_types.h
+++ b/linker/linker_common_types.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __LINKER_COMMON_TYPES_H
-#define __LINKER_COMMON_TYPES_H
+#pragma once
 
 #include <android/dlext.h>
 #include "linked_list.h"
@@ -65,5 +64,3 @@
 
 typedef LinkedList<soinfo, SoinfoListAllocator> soinfo_list_t;
 typedef LinkedList<android_namespace_t, NamespaceListAllocator> android_namespace_list_t;
-
-#endif  /* __LINKER_COMMON_TYPES_H */
diff --git a/linker/linker_config.h b/linker/linker_config.h
index 0c50d57..e117aea 100644
--- a/linker/linker_config.h
+++ b/linker/linker_config.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LINKER_CONFIG_H_
-#define _LINKER_CONFIG_H_
+#pragma once
 
 #include <android/api-level.h>
 
@@ -171,5 +170,3 @@
 
   DISALLOW_COPY_AND_ASSIGN(Config);
 };
-
-#endif /* _LINKER_CONFIG_H_ */
diff --git a/linker/linker_debug.h b/linker/linker_debug.h
index 7ceab08..862ea12 100644
--- a/linker/linker_debug.h
+++ b/linker/linker_debug.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LINKER_DEBUG_H_
-#define _LINKER_DEBUG_H_
+#pragma once
 
 // You can increase the verbosity of debug traces by defining the LD_DEBUG
 // environment variable to a numeric value from 0 to 2 (corresponding to
@@ -102,5 +101,3 @@
 #define MARK(x) do {} while (0)
 
 #endif
-
-#endif /* _LINKER_DEBUG_H_ */
diff --git a/linker/linker_dlwarning.h b/linker/linker_dlwarning.h
index 68827f7..af26824 100644
--- a/linker/linker_dlwarning.h
+++ b/linker/linker_dlwarning.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __LINKER_DLWARNING_H
-#define __LINKER_DLWARNING_H
+#pragma once
 
 void add_dlwarning(const char* sopath, const char* message, const char* value = nullptr);
 
@@ -36,5 +35,3 @@
 // is used to avoid forcing user into saving the message
 // to a global variable.
 void get_dlwarning(void* user_data, void (*f)(void*, const char*));
-
-#endif  /* __LINKER_DLWARNING_H */
diff --git a/linker/linker_gdb_support.h b/linker/linker_gdb_support.h
index 6709da1..4ae18ee 100644
--- a/linker/linker_gdb_support.h
+++ b/linker/linker_gdb_support.h
@@ -25,8 +25,8 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#ifndef __LINKER_GDB_SUPPORT_H
-#define __LINKER_GDB_SUPPORT_H
+
+#pragma once
 
 #include <link.h>
 #include <sys/cdefs.h>
@@ -42,5 +42,3 @@
 extern struct r_debug _r_debug;
 
 __END_DECLS
-
-#endif
diff --git a/linker/linker_globals.h b/linker/linker_globals.h
index 11ccbd5..b470918 100644
--- a/linker/linker_globals.h
+++ b/linker/linker_globals.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __LINKER_GLOBALS_H
-#define __LINKER_GLOBALS_H
+#pragma once
 
 #include <link.h>
 #include <stddef.h>
@@ -86,5 +85,3 @@
  private:
   std::string saved_error_msg_;
 };
-
-#endif  /* __LINKER_GLOBALS_H */
diff --git a/linker/linker_logger.h b/linker/linker_logger.h
index 3e53f74..9ce438e 100644
--- a/linker/linker_logger.h
+++ b/linker/linker_logger.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LINKER_LOGGER_H_
-#define _LINKER_LOGGER_H_
+#pragma once
 
 #include <stdlib.h>
 #include <limits.h>
@@ -61,5 +60,3 @@
 // If the system property debug.ld.greylist_disabled is true, we'll not use the greylist
 // regardless of API level.
 extern bool g_greylist_disabled;
-
-#endif /* _LINKER_LOGGER_H_ */
diff --git a/linker/linker_main.h b/linker/linker_main.h
index 5641696..8d486e8 100644
--- a/linker/linker_main.h
+++ b/linker/linker_main.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __LINKER_MAIN_H
-#define __LINKER_MAIN_H
+#pragma once
 
 #include <android/dlext.h>
 
@@ -71,5 +70,3 @@
 bool solist_remove_soinfo(soinfo* si);
 soinfo* solist_get_head();
 soinfo* solist_get_somain();
-
-#endif
diff --git a/linker/linker_mapped_file_fragment.h b/linker/linker_mapped_file_fragment.h
index 0bfc7a3..f7872bd 100644
--- a/linker/linker_mapped_file_fragment.h
+++ b/linker/linker_mapped_file_fragment.h
@@ -25,8 +25,8 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#ifndef LINKER_MAPPED_FILE_FRAGMENT_H
-#define LINKER_MAPPED_FILE_FRAGMENT_H
+
+#pragma once
 
 #include <unistd.h>
 
@@ -49,5 +49,3 @@
 
   DISALLOW_COPY_AND_ASSIGN(MappedFileFragment);
 };
-
-#endif /* LINKER_MAPPED_FILE_FRAGMENT_H */
diff --git a/linker/linker_namespaces.h b/linker/linker_namespaces.h
index a7fe0d5..03520d7 100644
--- a/linker/linker_namespaces.h
+++ b/linker/linker_namespaces.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __LINKER_NAMESPACES_H
-#define __LINKER_NAMESPACES_H
+#pragma once
 
 #include "linker_common_types.h"
 
@@ -164,5 +163,3 @@
 
   DISALLOW_COPY_AND_ASSIGN(android_namespace_t);
 };
-
-#endif  /* __LINKER_NAMESPACES_H */
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index d6276ed..9b9ce94 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -25,8 +25,8 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
-#ifndef LINKER_PHDR_H
-#define LINKER_PHDR_H
+
+#pragma once
 
 /* Declarations related to the ELF program header table and segments.
  *
@@ -134,5 +134,3 @@
 
 const char* phdr_table_get_interpreter_name(const ElfW(Phdr) * phdr_table, size_t phdr_count,
                                             ElfW(Addr) load_bias);
-
-#endif /* LINKER_PHDR_H */
diff --git a/linker/linker_reloc_iterators.h b/linker/linker_reloc_iterators.h
index 6340924..b162684 100644
--- a/linker/linker_reloc_iterators.h
+++ b/linker/linker_reloc_iterators.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __LINKER_RELOC_ITERATORS_H
-#define __LINKER_RELOC_ITERATORS_H
+#pragma once
 
 #include "linker.h"
 
@@ -173,5 +172,3 @@
   size_t relocation_group_index_;
   rel_t reloc_;
 };
-
-#endif  // __LINKER_RELOC_ITERATORS_H
diff --git a/linker/linker_relocs.h b/linker/linker_relocs.h
index ed00594..4bab0e0 100644
--- a/linker/linker_relocs.h
+++ b/linker/linker_relocs.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __LINKER_RELOCS_H
-#define __LINKER_RELOCS_H
+#pragma once
 
 #include <elf.h>
 
@@ -62,5 +61,3 @@
 #define R_GENERIC_IRELATIVE R_X86_64_IRELATIVE
 
 #endif
-
-#endif // __LINKER_RELOCS_H
diff --git a/linker/linker_sleb128.h b/linker/linker_sleb128.h
index 01e127d..6bb3199 100644
--- a/linker/linker_sleb128.h
+++ b/linker/linker_sleb128.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _LINKER_SLEB128_H
-#define _LINKER_SLEB128_H
+#pragma once
 
 #include <stdint.h>
 
@@ -70,5 +69,3 @@
   const uint8_t* current_;
   const uint8_t* const end_;
 };
-
-#endif // __LINKER_SLEB128_H
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 447c7c3..6e1f005 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __LINKER_SOINFO_H
-#define __LINKER_SOINFO_H
+#pragma once
 
 #include <link.h>
 
@@ -386,5 +385,3 @@
     }
   }
 }
-
-#endif  /* __LINKER_SOINFO_H */
diff --git a/linker/linker_utils.h b/linker/linker_utils.h
index e104a25..214646c 100644
--- a/linker/linker_utils.h
+++ b/linker/linker_utils.h
@@ -26,8 +26,7 @@
  * SUCH DAMAGE.
  */
 
-#ifndef __LINKER_UTILS_H
-#define __LINKER_UTILS_H
+#pragma once
 
 #include <string>
 #include <vector>
@@ -56,5 +55,3 @@
 off64_t page_start(off64_t offset);
 size_t page_offset(off64_t offset);
 bool safe_add(off64_t* out, off64_t a, size_t b);
-
-#endif
diff --git a/tests/utils.h b/tests/utils.h
index 3f4218e..f07bd58 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -140,15 +140,20 @@
   }
 }
 
-static inline void AssertChildExited(int pid, int expected_exit_status) {
+static inline void AssertChildExited(int pid, int expected_exit_status,
+                                     const std::string* error_msg = nullptr) {
   int status;
-  ASSERT_EQ(pid, TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)));
+  std::string error;
+  if (error_msg == nullptr) {
+    error_msg = &error;
+  }
+  ASSERT_EQ(pid, TEMP_FAILURE_RETRY(waitpid(pid, &status, 0))) << *error_msg;
   if (expected_exit_status >= 0) {
-    ASSERT_TRUE(WIFEXITED(status));
-    ASSERT_EQ(expected_exit_status, WEXITSTATUS(status));
+    ASSERT_TRUE(WIFEXITED(status)) << *error_msg;
+    ASSERT_EQ(expected_exit_status, WEXITSTATUS(status)) << *error_msg;
   } else {
-    ASSERT_TRUE(WIFSIGNALED(status));
-    ASSERT_EQ(-expected_exit_status, WTERMSIG(status));
+    ASSERT_TRUE(WIFSIGNALED(status)) << *error_msg;
+    ASSERT_EQ(-expected_exit_status, WTERMSIG(status)) << *error_msg;
   }
 }
 
@@ -215,7 +220,8 @@
     }
     close(fds[0]);
 
-    AssertChildExited(pid, expected_exit_status);
+    std::string error_msg("Test output:\n" + output);
+    AssertChildExited(pid, expected_exit_status, &error_msg);
     if (expected_output != nullptr) {
       ASSERT_EQ(expected_output, output);
     }