Avoid using new/delete in locale.cpp

This file is included in libandroid_support.a, where using new/delete
breaks libc++ tests that assume that libc++ makes no extraneous
new/delete calls.

This CL changes newlocale/duplocale to return NULL on out-of-memory.
Previously, the behavior varied:
 - libc.so: aborted using async_safe_fatal
 - libandroid_support.a: throws std::bad_alloc

Bug: none
Test: std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp
Test: libcxx/localization/locales/locale/locale.types/locale.facet/no_allocation.pass.cpp
Test: std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp
Change-Id: I38c772f249f32322afb9402ebeeb4bb65a908b59
diff --git a/libc/bionic/locale.cpp b/libc/bionic/locale.cpp
index 0b7037a..2f4d206 100644
--- a/libc/bionic/locale.cpp
+++ b/libc/bionic/locale.cpp
@@ -54,23 +54,23 @@
 
 struct __locale_t {
   size_t mb_cur_max;
-
-  explicit __locale_t(size_t mb_cur_max) : mb_cur_max(mb_cur_max) {
-  }
-
-  explicit __locale_t(const __locale_t* other) {
-    if (other == LC_GLOBAL_LOCALE) {
-      mb_cur_max = __bionic_current_locale_is_utf8 ? 4 : 1;
-    } else {
-      mb_cur_max = other->mb_cur_max;
-    }
-  }
-
-  BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(__locale_t);
 };
 
-size_t __ctype_get_mb_cur_max() {
-  locale_t l = uselocale(nullptr);
+// Avoid using new/delete in this file, because a user may have overridden
+// new/delete, and we want to avoid making extraneous calls to them. This isn't
+// an issue for libc.so in the platform, but this file is also compiled into the
+// NDK's libandroid_support.a, and there are libc++ tests that count the number
+// of calls to new/delete.
+#pragma clang poison new delete
+
+static inline locale_t __alloc_locale(size_t mb_cur_max) {
+  auto result = static_cast<__locale_t*>(malloc(sizeof(__locale_t)));
+  if (result == nullptr) return nullptr;
+  result->mb_cur_max = mb_cur_max;
+  return result;
+}
+
+static inline size_t get_locale_mb_cur_max(locale_t l) {
   if (l == LC_GLOBAL_LOCALE) {
     return __bionic_current_locale_is_utf8 ? 4 : 1;
   } else {
@@ -78,6 +78,10 @@
   }
 }
 
+size_t __ctype_get_mb_cur_max() {
+  return get_locale_mb_cur_max(uselocale(nullptr));
+}
+
 #if !USE_TLS_SLOT
 static thread_local locale_t g_current_locale;
 #endif
@@ -133,11 +137,11 @@
 }
 
 locale_t duplocale(locale_t l) {
-  return new __locale_t(l);
+  return __alloc_locale(get_locale_mb_cur_max(l));
 }
 
 void freelocale(locale_t l) {
-  delete l;
+  free(l);
 }
 
 locale_t newlocale(int category_mask, const char* locale_name, locale_t /*base*/) {
@@ -152,7 +156,7 @@
     return nullptr;
   }
 
-  return new __locale_t(__is_utf8_locale(locale_name) ? 4 : 1);
+  return __alloc_locale(__is_utf8_locale(locale_name) ? 4 : 1);
 }
 
 char* setlocale(int category, const char* locale_name) {