Merge "Document the intricacies of `_FILE_OFFSET_BITS=32` for LP32."
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
index 3f95aa1..0edba65 100644
--- a/benchmarks/Android.bp
+++ b/benchmarks/Android.bp
@@ -35,6 +35,17 @@
         "time_benchmark.cpp",
         "unistd_benchmark.cpp",
     ],
+    static_libs: ["libBionicBenchmarksUtils"],
+}
+
+cc_defaults {
+    name: "bionic-benchmarks-extras-defaults",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wunused",
+    ],
 }
 
 // Build benchmarks for the device (with bionic's .so). Run with:
@@ -63,3 +74,19 @@
         },
     },
 }
+
+cc_library_static {
+    name: "libBionicBenchmarksUtils",
+    defaults: ["bionic-benchmarks-extras-defaults"],
+    srcs: ["util.cpp"],
+    host_supported: true,
+}
+
+cc_test {
+    name: "bionic-benchmarks-tests",
+    defaults: ["bionic-benchmarks-extras-defaults"],
+    srcs: [
+        "tests/benchmark_test.cpp",
+    ],
+    static_libs: ["libBionicBenchmarksUtils"],
+}
diff --git a/benchmarks/string_benchmark.cpp b/benchmarks/string_benchmark.cpp
index 86a7c35..2ab65a8 100644
--- a/benchmarks/string_benchmark.cpp
+++ b/benchmarks/string_benchmark.cpp
@@ -18,188 +18,246 @@
 #include <string.h>
 
 #include <benchmark/benchmark.h>
+#include "util.h"
 
 constexpr auto KB = 1024;
 
-#define AT_COMMON_SIZES \
-    Arg(8)->Arg(64)->Arg(512)->Arg(1*KB)->Arg(8*KB)->Arg(16*KB)->Arg(32*KB)->Arg(64*KB)
+// NOTE: these constants are temporary replacements for AT_COMMON_SIZES until
+// the new interface for Bionic benchmarks is implemented.
 
-// TODO: test unaligned operation too? (currently everything will be 8-byte aligned by malloc.)
+// Set all four to 0 to test normal alignment.
+#define AT_SRC_ALIGN 0
+#define AT_DST_ALIGN 0
+
+#define AT_ALIGNED_TWOBUF \
+    Args({(8), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(64), AT_SRC_ALIGN, AT_DST_ALIGN})-> \
+    Args({(512), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(1*KB), AT_SRC_ALIGN, AT_DST_ALIGN})-> \
+    Args({(8*KB), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(16*KB), AT_SRC_ALIGN, AT_DST_ALIGN})-> \
+    Args({(32*KB), AT_SRC_ALIGN, AT_DST_ALIGN})->Args({(64*KB), AT_SRC_ALIGN, AT_DST_ALIGN})
+
+#define AT_ALIGNED_ONEBUF \
+    Args({(8), AT_SRC_ALIGN})->Args({(64), AT_SRC_ALIGN})->Args({(512), AT_SRC_ALIGN})-> \
+    Args({(1*KB), AT_SRC_ALIGN})->Args({(8*KB), AT_SRC_ALIGN})->Args({(16*KB), AT_SRC_ALIGN})-> \
+    Args({(32*KB), AT_SRC_ALIGN})->Args({(64*KB), AT_SRC_ALIGN})
 
 static void BM_string_memcmp(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  char* src = new char[nbytes]; char* dst = new char[nbytes];
-  memset(src, 'x', nbytes);
-  memset(dst, 'x', nbytes);
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+  char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'x');
 
   volatile int c __attribute__((unused)) = 0;
   while (state.KeepRunning()) {
-    c += memcmp(dst, src, nbytes);
+    c += memcmp(dst_aligned, src_aligned, nbytes);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
-  delete[] src;
-  delete[] dst;
 }
-BENCHMARK(BM_string_memcmp)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memcmp)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_memcpy(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  char* src = new char[nbytes]; char* dst = new char[nbytes];
-  memset(src, 'x', nbytes);
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+  char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes);
 
   while (state.KeepRunning()) {
-    memcpy(dst, src, nbytes);
+    memcpy(dst_aligned, src_aligned, nbytes);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
-  delete[] src;
-  delete[] dst;
 }
-BENCHMARK(BM_string_memcpy)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memcpy)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_memmove_non_overlapping(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> src(nbytes, 'x');
-  std::vector<char> dst(nbytes, 'x');
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+  char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'y');
 
   while (state.KeepRunning()) {
-    memmove(dst.data(), src.data(), nbytes);
+    memmove(dst_aligned, src_aligned, nbytes);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_memmove_non_overlapping)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memmove_non_overlapping)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_memmove_overlap_dst_before_src(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> buf(nbytes + 1, 'x');
+  const size_t alignment = state.range(1);
+
+  std::vector<char> buf(3 * alignment + nbytes + 1, 'x');
+  char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
 
   while (state.KeepRunning()) {
-    memmove(buf.data(), buf.data() + 1, nbytes); // Worst-case overlap.
+    memmove(buf_aligned, buf_aligned + 1, nbytes);  // Worst-case overlap.
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_memmove_overlap_dst_before_src)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memmove_overlap_dst_before_src)->AT_ALIGNED_ONEBUF;
 
 static void BM_string_memmove_overlap_src_before_dst(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> buf(nbytes + 1, 'x');
+  const size_t alignment = state.range(1);
+
+  std::vector<char> buf;
+  char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
 
   while (state.KeepRunning()) {
-    memmove(buf.data() + 1, buf.data(), nbytes); // Worst-case overlap.
+    memmove(buf_aligned + 1, buf_aligned, nbytes);  // Worst-case overlap.
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_memmove_overlap_src_before_dst)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memmove_overlap_src_before_dst)->AT_ALIGNED_ONEBUF;
 
 static void BM_string_memset(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  char* dst = new char[nbytes];
+  const size_t alignment = state.range(1);
+
+  std::vector<char> buf;
+  char* buf_aligned = GetAlignedPtr(&buf, alignment, nbytes + 1);
 
   while (state.KeepRunning()) {
-    memset(dst, 0, nbytes);
+    memset(buf_aligned, 0, nbytes);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
-  delete[] dst;
 }
-BENCHMARK(BM_string_memset)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_memset)->AT_ALIGNED_ONEBUF;
 
 static void BM_string_strlen(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  char* s = new char[nbytes];
-  memset(s, 'x', nbytes);
-  s[nbytes - 1] = 0;
+  const size_t alignment = state.range(1);
+
+  std::vector<char> buf;
+  char* buf_aligned = GetAlignedPtrFilled(&buf, alignment, nbytes + 1, 'x');
+  buf_aligned[nbytes - 1] = '\0';
 
   volatile int c __attribute__((unused)) = 0;
   while (state.KeepRunning()) {
-    c += strlen(s);
+    c += strlen(buf_aligned);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
-  delete[] s;
 }
-BENCHMARK(BM_string_strlen)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strlen)->AT_ALIGNED_ONEBUF;
 
 static void BM_string_strcat_copy_only(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> src(nbytes, 'x');
-  std::vector<char> dst(nbytes + 2);
-  src[nbytes - 1] = '\0';
-  dst[0] = 'y';
-  dst[1] = 'y';
-  dst[2] = '\0';
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+  char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes + 2);
+  src_aligned[nbytes - 1] = '\0';
+  dst_aligned[0] = 'y';
+  dst_aligned[1] = 'y';
+  dst_aligned[2] = '\0';
 
   while (state.KeepRunning()) {
-    strcat(dst.data(), src.data());
-    dst[2] = '\0';
+    strcat(dst_aligned, src_aligned);
+    dst_aligned[2] = '\0';
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcat_copy_only)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcat_copy_only)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_strcat_seek_only(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> src(3, 'x');
-  std::vector<char> dst(nbytes + 2, 'y');
-  src[2] = '\0';
-  dst[nbytes - 1] = '\0';
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, 3, 'x');
+  char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes + 2, 'y');
+  src_aligned[2] = '\0';
+  dst_aligned[nbytes - 1] = '\0';
 
   while (state.KeepRunning()) {
-    strcat(dst.data(), src.data());
-    dst[nbytes - 1] = '\0';
+    strcat(dst_aligned, src_aligned);
+    dst_aligned[nbytes - 1] = '\0';
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcat_seek_only)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcat_seek_only)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_strcat_half_copy_half_seek(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> src(nbytes / 2, 'x');
-  std::vector<char> dst(nbytes / 2, 'y');
-  src[nbytes / 2 - 1] = '\0';
-  dst[nbytes / 2 - 1] = '\0';
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes / 2, 'x');
+  char* dst_aligned = GetAlignedPtrFilled(&dst, dst_alignment, nbytes, 'y');
+  src_aligned[nbytes / 2 - 1] = '\0';
+  dst_aligned[nbytes / 2 - 1] = '\0';
 
   while (state.KeepRunning()) {
-    strcat(dst.data(), src.data());
-    dst[nbytes / 2 - 1] = '\0';
+    strcat(dst_aligned, src_aligned);
+    dst_aligned[nbytes / 2 - 1] = '\0';
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcat_half_copy_half_seek)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcat_half_copy_half_seek)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_strcpy(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> src(nbytes, 'x');
-  std::vector<char> dst(nbytes);
-  src[nbytes - 1] = '\0';
+  const size_t src_alignment = state.range(1);
+  const size_t dst_alignment = state.range(2);
+
+  std::vector<char> src;
+  std::vector<char> dst;
+  char* src_aligned = GetAlignedPtrFilled(&src, src_alignment, nbytes, 'x');
+  char* dst_aligned = GetAlignedPtr(&dst, dst_alignment, nbytes);
+  src_aligned[nbytes - 1] = '\0';
 
   while (state.KeepRunning()) {
-    strcpy(dst.data(), src.data());
+    strcpy(dst_aligned, src_aligned);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcpy)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcpy)->AT_ALIGNED_TWOBUF;
 
 static void BM_string_strcmp(benchmark::State& state) {
   const size_t nbytes = state.range(0);
-  std::vector<char> s1(nbytes, 'x');
-  std::vector<char> s2(nbytes, 'x');
-  s1[nbytes - 1] = '\0';
-  s2[nbytes - 1] = '\0';
+  const size_t s1_alignment = state.range(1);
+  const size_t s2_alignment = state.range(2);
+
+  std::vector<char> s1;
+  std::vector<char> s2;
+  char* s1_aligned = GetAlignedPtrFilled(&s1, s1_alignment, nbytes, 'x');
+  char* s2_aligned = GetAlignedPtrFilled(&s2, s2_alignment, nbytes, 'x');
+  s1_aligned[nbytes - 1] = '\0';
+  s2_aligned[nbytes - 1] = '\0';
 
   volatile int c __attribute__((unused));
   while (state.KeepRunning()) {
-    c = strcmp(s1.data(), s2.data());
+    c = strcmp(s1_aligned, s2_aligned);
   }
 
   state.SetBytesProcessed(uint64_t(state.iterations()) * uint64_t(nbytes));
 }
-BENCHMARK(BM_string_strcmp)->AT_COMMON_SIZES;
+BENCHMARK(BM_string_strcmp)->AT_ALIGNED_TWOBUF;
diff --git a/benchmarks/tests/benchmark_test.cpp b/benchmarks/tests/benchmark_test.cpp
new file mode 100644
index 0000000..df7b686
--- /dev/null
+++ b/benchmarks/tests/benchmark_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <util.h>
+
+TEST(benchmark, memory_align) {
+  std::vector<char> buf(100);
+  for (size_t alignment = 1; alignment <= 32; alignment *= 2) {
+    for (size_t or_mask = 0; or_mask < alignment; ++or_mask) {
+      uintptr_t aligned_ptr = reinterpret_cast<uintptr_t>(GetAlignedMemory(buf.data(), alignment,
+                                                                           or_mask));
+      ASSERT_EQ(aligned_ptr % alignment, or_mask);
+      ASSERT_EQ(aligned_ptr & alignment, alignment);
+    }
+  }
+}
+
+TEST(benchmark, ptr_align) {
+  std::vector<char> buf;
+  for (size_t alignment = 1; alignment <= 2048; alignment *= 2) {
+    uintptr_t aligned_ptr = reinterpret_cast<uintptr_t>(GetAlignedPtr(&buf, alignment, 100));
+    ASSERT_EQ(aligned_ptr & alignment, alignment);
+    ASSERT_EQ(aligned_ptr & (alignment - 1), 0u);
+  }
+}
diff --git a/benchmarks/util.cpp b/benchmarks/util.cpp
new file mode 100644
index 0000000..d9641cf
--- /dev/null
+++ b/benchmarks/util.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util.h"
+
+#include <sched.h>
+#include <stdio.h>
+#include <string.h>
+#include <cstdlib>
+#include <vector>
+
+// This function returns a pointer less than 2 * alignment + or_mask bytes into the array.
+char *GetAlignedMemory(char *orig_ptr, size_t alignment, size_t or_mask) {
+  if ((alignment & (alignment - 1)) != 0) {
+    fprintf(stderr, "warning: alignment passed into GetAlignedMemory is not a power of two.\n");
+    std::abort();
+  }
+  if (or_mask > alignment) {
+    fprintf(stderr, "warning: or_mask passed into GetAlignedMemory is too high.\n");
+    std::abort();
+  }
+  uintptr_t ptr = reinterpret_cast<uintptr_t>(orig_ptr);
+  if (alignment > 0) {
+    // When setting the alignment, set it to exactly the alignment chosen.
+    // The pointer returned will be guaranteed not to be aligned to anything
+    // more than that.
+    ptr += alignment - (ptr & (alignment - 1));
+    ptr |= alignment | or_mask;
+  }
+
+  return reinterpret_cast<char*>(ptr);
+}
+
+char *GetAlignedPtr(std::vector<char>* buf, size_t alignment, size_t nbytes) {
+  buf->resize(nbytes + 3 * alignment);
+  return GetAlignedMemory(buf->data(), alignment, 0);
+}
+
+char *GetAlignedPtrFilled(std::vector<char>* buf, size_t alignment, size_t nbytes, char fill_byte) {
+  char* buf_aligned = GetAlignedPtr(buf, alignment, nbytes);
+  memset(buf_aligned, fill_byte, nbytes);
+  return buf_aligned;
+}
+
+#if defined(__APPLE__)
+
+// Darwin doesn't support this, so do nothing.
+bool LockToCPU(int) {
+  return false;
+}
+
+#else
+
+bool LockToCPU(int cpu_to_lock) {
+  cpu_set_t cpuset;
+
+  CPU_ZERO(&cpuset);
+  if (sched_getaffinity(0, sizeof(cpuset), &cpuset) != 0) {
+    perror("sched_getaffinity failed");
+    return false;
+  }
+
+  if (cpu_to_lock < 0) {
+    // Lock to the last active core we find.
+    for (int i = 0; i < CPU_SETSIZE; i++) {
+      if (CPU_ISSET(i, &cpuset)) {
+        cpu_to_lock = i;
+      }
+    }
+  } else if (!CPU_ISSET(cpu_to_lock, &cpuset)) {
+    printf("Cpu %d does not exist.\n", cpu_to_lock);
+    return false;
+  }
+
+  if (cpu_to_lock < 0) {
+    printf("Cannot find any valid cpu to lock.\n");
+    return false;
+  }
+
+  CPU_ZERO(&cpuset);
+  CPU_SET(cpu_to_lock, &cpuset);
+  if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
+    perror("sched_setaffinity failed");
+    return false;
+  }
+
+  return true;
+}
+
+#endif
diff --git a/benchmarks/util.h b/benchmarks/util.h
new file mode 100644
index 0000000..bd3d515
--- /dev/null
+++ b/benchmarks/util.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BIONIC_BENCHMARKS_UTIL_H_
+#define _BIONIC_BENCHMARKS_UTIL_H_
+
+#include <vector>
+
+// This function returns a pointer less than 2 * alignment + or_mask bytes into the array.
+char *GetAlignedMemory(char *orig_ptr, size_t alignment, size_t or_mask);
+
+char *GetAlignedPtr(std::vector<char>* buf, size_t alignment, size_t nbytes);
+
+char *GetAlignedPtrFilled(std::vector<char>* buf, size_t alignment, size_t nbytes, char fill_byte);
+
+bool LockToCPU(int cpu_to_lock);
+
+#endif // _BIONIC_BENCHMARKS_UTIL_H
diff --git a/libc/Android.bp b/libc/Android.bp
index cd2a727..7b0ac23 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1330,6 +1330,13 @@
 cc_library_static {
     defaults: ["libc_defaults"],
     srcs: [
+        "bionic/NetdClientDispatch.cpp",
+        "bionic/__cmsg_nxthdr.cpp",
+        "bionic/__errno.cpp",
+        "bionic/__gnu_basename.cpp",
+        "bionic/__libc_current_sigrtmax.cpp",
+        "bionic/__libc_current_sigrtmin.cpp",
+        "bionic/__set_errno.cpp",
         "bionic/abort.cpp",
         "bionic/accept.cpp",
         "bionic/accept4.cpp",
@@ -1352,7 +1359,6 @@
         "bionic/clock_nanosleep.cpp",
         "bionic/clone.cpp",
         "bionic/close.cpp",
-        "bionic/__cmsg_nxthdr.cpp",
         "bionic/connect.cpp",
         "bionic/ctype.cpp",
         "bionic/dirent.cpp",
@@ -1361,7 +1367,6 @@
         "bionic/epoll_create.cpp",
         "bionic/epoll_pwait.cpp",
         "bionic/epoll_wait.cpp",
-        "bionic/__errno.cpp",
         "bionic/error.cpp",
         "bionic/eventfd_read.cpp",
         "bionic/eventfd_write.cpp",
@@ -1387,7 +1392,6 @@
         "bionic/getpid.cpp",
         "bionic/getpriority.cpp",
         "bionic/gettid.cpp",
-        "bionic/__gnu_basename.cpp",
         "bionic/grp_pwd.cpp",
         "bionic/ifaddrs.cpp",
         "bionic/inotify_init.cpp",
@@ -1395,8 +1399,6 @@
         "bionic/langinfo.cpp",
         "bionic/lchown.cpp",
         "bionic/lfs64_support.cpp",
-        "bionic/__libc_current_sigrtmax.cpp",
-        "bionic/__libc_current_sigrtmin.cpp",
         "bionic/libc_init_common.cpp",
         "bionic/libgen.cpp",
         "bionic/link.cpp",
@@ -1407,7 +1409,6 @@
         "bionic/mblen.cpp",
         "bionic/mbrtoc16.cpp",
         "bionic/mbrtoc32.cpp",
-        "bionic/mbstate.cpp",
         "bionic/memmem.cpp",
         "bionic/mempcpy.cpp",
         "bionic/mkdir.cpp",
@@ -1415,9 +1416,8 @@
         "bionic/mknod.cpp",
         "bionic/mntent.cpp",
         "bionic/mremap.cpp",
-        "bionic/netdb.cpp",
-        "bionic/NetdClientDispatch.cpp",
         "bionic/net_if.cpp",
+        "bionic/netdb.cpp",
         "bionic/netinet_in.cpp",
         "bionic/nl_types.cpp",
         "bionic/open.cpp",
@@ -1444,7 +1444,6 @@
         "bionic/semaphore.cpp",
         "bionic/send.cpp",
         "bionic/setegid.cpp",
-        "bionic/__set_errno.cpp",
         "bionic/seteuid.cpp",
         "bionic/setpgrp.cpp",
         "bionic/sigaction.cpp",
@@ -1470,21 +1469,24 @@
         "bionic/socket.cpp",
         "bionic/stat.cpp",
         "bionic/statvfs.cpp",
+        "bionic/stdlib_l.cpp",
         "bionic/strchrnul.cpp",
         "bionic/strerror.cpp",
         "bionic/strerror_r.cpp",
+        "bionic/string_l.cpp",
+        "bionic/strings_l.cpp",
         "bionic/strsignal.cpp",
         "bionic/strtold.cpp",
         "bionic/symlink.cpp",
         "bionic/sync_file_range.cpp",
-        "bionic/sysinfo.cpp",
-        "bionic/syslog.cpp",
         "bionic/sys_msg.cpp",
         "bionic/sys_sem.cpp",
         "bionic/sys_shm.cpp",
         "bionic/sys_siglist.c",
         "bionic/sys_signame.c",
         "bionic/sys_time.cpp",
+        "bionic/sysinfo.cpp",
+        "bionic/syslog.cpp",
         "bionic/system_properties.cpp",
         "bionic/tdestroy.cpp",
         "bionic/termios.cpp",
@@ -1494,6 +1496,7 @@
         "bionic/unlink.cpp",
         "bionic/wait.cpp",
         "bionic/wchar.cpp",
+        "bionic/wchar_l.cpp",
         "bionic/wcstod.cpp",
         "bionic/wctype.cpp",
         "bionic/wmempcpy.cpp",
diff --git a/libc/NOTICE b/libc/NOTICE
index bcc9691..ae98d1d 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -862,22 +862,6 @@
 
      http://www.apache.org/licenses/LICENSE-2.0
 
- Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
--------------------------------------------------------------------
-
-Copyright (C) 2015 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -5403,32 +5387,6 @@
 
 -------------------------------------------------------------------
 
-Copyright (c) 2013 David Chisnall
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. 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 AUTHOR 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 AUTHOR 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.
-
--------------------------------------------------------------------
-
 Copyright (c) 2013 The NetBSD Foundation, Inc.
 All rights reserved.
 
diff --git a/libc/bionic/c16rtomb.cpp b/libc/bionic/c16rtomb.cpp
index 77512be..93749c6 100644
--- a/libc/bionic/c16rtomb.cpp
+++ b/libc/bionic/c16rtomb.cpp
@@ -50,18 +50,18 @@
       mbstate_set_byte(state, 2, (c32 & 0x00ff00) >> 8);
       return 0;
     } else if (is_low_surrogate(c16)) {
-      return reset_and_return_illegal(EINVAL, state);
+      return mbstate_reset_and_return_illegal(EINVAL, state);
     } else {
       return c32rtomb(s, static_cast<char32_t>(c16), state);
     }
   } else {
     if (!is_low_surrogate(c16)) {
-      return reset_and_return_illegal(EINVAL, state);
+      return mbstate_reset_and_return_illegal(EINVAL, state);
     }
 
     char32_t c32 = ((mbstate_get_byte(state, 3) << 16) |
                     (mbstate_get_byte(state, 2) << 8) |
                     (c16 & ~0xdc00)) + 0x10000;
-    return reset_and_return(c32rtomb(s, c32, NULL), state);
+    return mbstate_reset_and_return(c32rtomb(s, c32, NULL), state);
   }
 }
diff --git a/libc/bionic/c32rtomb.cpp b/libc/bionic/c32rtomb.cpp
index d3231c0..ebe9cd3 100644
--- a/libc/bionic/c32rtomb.cpp
+++ b/libc/bionic/c32rtomb.cpp
@@ -38,7 +38,7 @@
 
   if (s == NULL) {
     // Equivalent to c32rtomb(buf, U'\0', ps).
-    return reset_and_return(1, state);
+    return mbstate_reset_and_return(1, state);
   }
 
   // POSIX states that if char32_t is a null wide character, a null byte shall
@@ -47,11 +47,11 @@
   // stored.
   if (c32 == U'\0') {
     *s = '\0';
-    reset_and_return(1, state);
+    return mbstate_reset_and_return(1, state);
   }
 
   if (!mbsinit(state)) {
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
 
   if ((c32 & ~0x7f) == 0) {
diff --git a/libc/bionic/locale.cpp b/libc/bionic/locale.cpp
index 38e15b7..08c9401 100644
--- a/libc/bionic/locale.cpp
+++ b/libc/bionic/locale.cpp
@@ -37,7 +37,15 @@
 
 #include "private/bionic_macros.h"
 
+#if defined(__BIONIC_BUILD_FOR_ANDROID_SUPPORT)
+#define USE_TLS_SLOT 0
+#else
+#define USE_TLS_SLOT 1
+#endif
+
+#if USE_TLS_SLOT
 #include "bionic/pthread_internal.h"
+#endif
 
 // We only support two locales, the "C" locale (also known as "POSIX"),
 // and the "C.UTF-8" locale (also known as "en_US.UTF-8").
@@ -70,6 +78,10 @@
   }
 }
 
+#if !USE_TLS_SLOT
+static thread_local locale_t g_current_locale;
+#endif
+
 static pthread_once_t g_locale_once = PTHREAD_ONCE_INIT;
 static lconv g_locale;
 
@@ -163,9 +175,16 @@
   return const_cast<char*>(__bionic_current_locale_is_utf8 ? "C.UTF-8" : "C");
 }
 
+static locale_t* get_current_locale_ptr() {
+#if USE_TLS_SLOT
+  return &__get_bionic_tls().locale;
+#else
+  return &g_current_locale;
+#endif
+}
+
 locale_t uselocale(locale_t new_locale) {
-  locale_t* locale_storage = &__get_bionic_tls().locale;
-  locale_t old_locale = *locale_storage;
+  locale_t old_locale = *get_current_locale_ptr();
 
   // If this is the first call to uselocale(3) on this thread, we return LC_GLOBAL_LOCALE.
   if (old_locale == NULL) {
@@ -173,64 +192,8 @@
   }
 
   if (new_locale != NULL) {
-    *locale_storage = new_locale;
+    *get_current_locale_ptr() = new_locale;
   }
 
   return old_locale;
 }
-
-int strcasecmp_l(const char* s1, const char* s2, locale_t) {
-  return strcasecmp(s1, s2);
-}
-
-int strcoll_l(const char* s1, const char* s2, locale_t) {
-  return strcoll(s1, s2);
-}
-
-char* strerror_l(int error, locale_t) {
-  return strerror(error);
-}
-
-int strncasecmp_l(const char* s1, const char* s2, size_t n, locale_t) {
-  return strncasecmp(s1, s2, n);
-}
-
-double strtod_l(const char* s, char** end_ptr, locale_t) {
-  return strtod(s, end_ptr);
-}
-
-float strtof_l(const char* s, char** end_ptr, locale_t) {
-  return strtof(s, end_ptr);
-}
-
-long strtol_l(const char* s, char** end_ptr, int base, locale_t) {
-  return strtol(s, end_ptr, base);
-}
-
-long double strtold_l(const char* s, char** end_ptr, locale_t) {
-  return strtold(s, end_ptr);
-}
-
-long long strtoll_l(const char* s, char** end_ptr, int base, locale_t) {
-  return strtoll(s, end_ptr, base);
-}
-
-unsigned long strtoul_l(const char* s, char** end_ptr, int base, locale_t) {
-  return strtoul(s, end_ptr, base);
-}
-
-unsigned long long strtoull_l(const char* s, char** end_ptr, int base, locale_t) {
-  return strtoull(s, end_ptr, base);
-}
-
-size_t strxfrm_l(char* dst, const char* src, size_t n, locale_t) {
-  return strxfrm(dst, src, n);
-}
-
-int wcscasecmp_l(const wchar_t* ws1, const wchar_t* ws2, locale_t) {
-  return wcscasecmp(ws1, ws2);
-}
-
-int wcsncasecmp_l(const wchar_t* ws1, const wchar_t* ws2, size_t n, locale_t) {
-  return wcsncasecmp(ws1, ws2, n);
-}
diff --git a/libc/bionic/mbrtoc16.cpp b/libc/bionic/mbrtoc16.cpp
index 6878a11..2180516 100644
--- a/libc/bionic/mbrtoc16.cpp
+++ b/libc/bionic/mbrtoc16.cpp
@@ -55,7 +55,7 @@
   char16_t trail = mbstate_get_byte(state, 1) << 8 |
                    mbstate_get_byte(state, 0);
   *pc16 = trail;
-  return reset_and_return(mbstate_get_byte(state, 3), state);
+  return mbstate_reset_and_return(mbstate_get_byte(state, 3), state);
 }
 
 size_t mbrtoc16(char16_t* pc16, const char* s, size_t n, mbstate_t* ps) {
@@ -76,13 +76,13 @@
   if (__MB_IS_ERR(nconv)) {
     return nconv;
   } else if (nconv == 0) {
-    return reset_and_return(nconv, state);
+    return mbstate_reset_and_return(nconv, state);
   } else if (c32 > 0x10ffff) {
     // Input cannot be encoded as UTF-16.
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   } else if (c32 < 0x10000) {
     *pc16 = static_cast<char16_t>(c32);
-    return reset_and_return(nconv, state);
+    return mbstate_reset_and_return(nconv, state);
   } else {
     return begin_surrogate(c32, pc16, nconv, state);
   }
diff --git a/libc/bionic/mbrtoc32.cpp b/libc/bionic/mbrtoc32.cpp
index bd40ecf..f004b78 100644
--- a/libc/bionic/mbrtoc32.cpp
+++ b/libc/bionic/mbrtoc32.cpp
@@ -41,7 +41,7 @@
   // Full state verification is done when decoding the sequence (after we have
   // all the bytes).
   if (mbstate_get_byte(state, 3) != 0) {
-    return reset_and_return_illegal(EINVAL, state);
+    return mbstate_reset_and_return_illegal(EINVAL, state);
   }
 
   if (s == NULL) {
@@ -98,7 +98,7 @@
     lower_bound = 0x10000;
   } else {
     // Malformed input; input is not UTF-8. See RFC 3629.
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
 
   // Fill in the state.
@@ -107,7 +107,7 @@
   for (i = 0; i < MIN(bytes_wanted, n); i++) {
     if (!mbsinit(state) && ((*s & 0xc0) != 0x80)) {
       // Malformed input; bad characters in the middle of a character.
-      return reset_and_return_illegal(EILSEQ, state);
+      return mbstate_reset_and_return_illegal(EILSEQ, state);
     }
     mbstate_set_byte(state, bytes_so_far + i, *s++);
   }
@@ -125,14 +125,14 @@
 
   if (c32 < lower_bound) {
     // Malformed input; redundant encoding.
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
   if ((c32 >= 0xd800 && c32 <= 0xdfff) || c32 == 0xfffe || c32 == 0xffff) {
     // Malformed input; invalid code points.
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
   if (pc32 != NULL) {
     *pc32 = c32;
   }
-  return reset_and_return(c32 == U'\0' ? 0 : bytes_wanted, state);
+  return mbstate_reset_and_return(c32 == U'\0' ? 0 : bytes_wanted, state);
 }
diff --git a/libc/bionic/mbstate.cpp b/libc/bionic/stdlib_l.cpp
similarity index 62%
rename from libc/bionic/mbstate.cpp
rename to libc/bionic/stdlib_l.cpp
index cb327d8..18e9f86 100644
--- a/libc/bionic/mbstate.cpp
+++ b/libc/bionic/stdlib_l.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,32 +26,34 @@
  * SUCH DAMAGE.
  */
 
-#include "private/bionic_mbstate.h"
+#include <stdlib.h>
+#include <xlocale.h>
 
-#include <errno.h>
-
-__LIBC_HIDDEN__ size_t mbstate_bytes_so_far(const mbstate_t* ps) {
-  return
-    (ps->__seq[2] != 0) ? 3 :
-    (ps->__seq[1] != 0) ? 2 :
-    (ps->__seq[0] != 0) ? 1 : 0;
+double strtod_l(const char* s, char** end_ptr, locale_t) {
+  return strtod(s, end_ptr);
 }
 
-__LIBC_HIDDEN__ void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
-  ps->__seq[i] = static_cast<uint8_t>(byte);
+float strtof_l(const char* s, char** end_ptr, locale_t) {
+  return strtof(s, end_ptr);
 }
 
-__LIBC_HIDDEN__ uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
-  return ps->__seq[n];
+long strtol_l(const char* s, char** end_ptr, int base, locale_t) {
+  return strtol(s, end_ptr, base);
 }
 
-__LIBC_HIDDEN__ size_t reset_and_return_illegal(int _errno, mbstate_t* ps) {
-  errno = _errno;
-  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
-  return __MB_ERR_ILLEGAL_SEQUENCE;
+long double strtold_l(const char* s, char** end_ptr, locale_t) {
+  return strtold(s, end_ptr);
 }
 
-__LIBC_HIDDEN__ size_t reset_and_return(int _return, mbstate_t* ps) {
-  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
-  return _return;
+long long strtoll_l(const char* s, char** end_ptr, int base, locale_t) {
+  return strtoll(s, end_ptr, base);
 }
+
+unsigned long strtoul_l(const char* s, char** end_ptr, int base, locale_t) {
+  return strtoul(s, end_ptr, base);
+}
+
+unsigned long long strtoull_l(const char* s, char** end_ptr, int base, locale_t) {
+  return strtoull(s, end_ptr, base);
+}
+
diff --git a/libc/bionic/mbstate.cpp b/libc/bionic/string_l.cpp
similarity index 62%
copy from libc/bionic/mbstate.cpp
copy to libc/bionic/string_l.cpp
index cb327d8..66bfb0e 100644
--- a/libc/bionic/mbstate.cpp
+++ b/libc/bionic/string_l.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,32 +26,17 @@
  * SUCH DAMAGE.
  */
 
-#include "private/bionic_mbstate.h"
+#include <string.h>
+#include <xlocale.h>
 
-#include <errno.h>
-
-__LIBC_HIDDEN__ size_t mbstate_bytes_so_far(const mbstate_t* ps) {
-  return
-    (ps->__seq[2] != 0) ? 3 :
-    (ps->__seq[1] != 0) ? 2 :
-    (ps->__seq[0] != 0) ? 1 : 0;
+int strcoll_l(const char* s1, const char* s2, locale_t) {
+  return strcoll(s1, s2);
 }
 
-__LIBC_HIDDEN__ void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
-  ps->__seq[i] = static_cast<uint8_t>(byte);
+char* strerror_l(int error, locale_t) {
+  return strerror(error);
 }
 
-__LIBC_HIDDEN__ uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
-  return ps->__seq[n];
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return_illegal(int _errno, mbstate_t* ps) {
-  errno = _errno;
-  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
-  return __MB_ERR_ILLEGAL_SEQUENCE;
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return(int _return, mbstate_t* ps) {
-  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
-  return _return;
+size_t strxfrm_l(char* dst, const char* src, size_t n, locale_t) {
+  return strxfrm(dst, src, n);
 }
diff --git a/libc/bionic/mbstate.cpp b/libc/bionic/strings_l.cpp
similarity index 62%
copy from libc/bionic/mbstate.cpp
copy to libc/bionic/strings_l.cpp
index cb327d8..0983ab1 100644
--- a/libc/bionic/mbstate.cpp
+++ b/libc/bionic/strings_l.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,32 +26,13 @@
  * SUCH DAMAGE.
  */
 
-#include "private/bionic_mbstate.h"
+#include <strings.h>
+#include <xlocale.h>
 
-#include <errno.h>
-
-__LIBC_HIDDEN__ size_t mbstate_bytes_so_far(const mbstate_t* ps) {
-  return
-    (ps->__seq[2] != 0) ? 3 :
-    (ps->__seq[1] != 0) ? 2 :
-    (ps->__seq[0] != 0) ? 1 : 0;
+int strcasecmp_l(const char* s1, const char* s2, locale_t) {
+  return strcasecmp(s1, s2);
 }
 
-__LIBC_HIDDEN__ void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
-  ps->__seq[i] = static_cast<uint8_t>(byte);
-}
-
-__LIBC_HIDDEN__ uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
-  return ps->__seq[n];
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return_illegal(int _errno, mbstate_t* ps) {
-  errno = _errno;
-  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
-  return __MB_ERR_ILLEGAL_SEQUENCE;
-}
-
-__LIBC_HIDDEN__ size_t reset_and_return(int _return, mbstate_t* ps) {
-  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
-  return _return;
+int strncasecmp_l(const char* s1, const char* s2, size_t n, locale_t) {
+  return strncasecmp(s1, s2, n);
 }
diff --git a/libc/bionic/wchar.cpp b/libc/bionic/wchar.cpp
index 7717e10..62023d6 100644
--- a/libc/bionic/wchar.cpp
+++ b/libc/bionic/wchar.cpp
@@ -74,7 +74,7 @@
   // character appears as anything but the first byte of a
   // multibyte sequence. Check now to avoid doing it in the loops.
   if (nmc > 0 && mbstate_bytes_so_far(state) > 0 && static_cast<uint8_t>((*src)[0]) < 0x80) {
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
 
   // Measure only?
@@ -83,23 +83,23 @@
       if (static_cast<uint8_t>((*src)[i]) < 0x80) {
         // Fast path for plain ASCII characters.
         if ((*src)[i] == '\0') {
-          return reset_and_return(o, state);
+          return mbstate_reset_and_return(o, state);
         }
         r = 1;
       } else {
         r = mbrtowc(NULL, *src + i, nmc - i, state);
         if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
-          return reset_and_return_illegal(EILSEQ, state);
+          return mbstate_reset_and_return_illegal(EILSEQ, state);
         }
         if (r == __MB_ERR_INCOMPLETE_SEQUENCE) {
-          return reset_and_return_illegal(EILSEQ, state);
+          return mbstate_reset_and_return_illegal(EILSEQ, state);
         }
         if (r == 0) {
-          return reset_and_return(o, state);
+          return mbstate_reset_and_return(o, state);
         }
       }
     }
-    return reset_and_return(o, state);
+    return mbstate_reset_and_return(o, state);
   }
 
   // Actually convert, updating `dst` and `src`.
@@ -110,26 +110,26 @@
       r = 1;
       if ((*src)[i] == '\0') {
         *src = nullptr;
-        return reset_and_return(o, state);
+        return mbstate_reset_and_return(o, state);
       }
     } else {
       r = mbrtowc(dst + o, *src + i, nmc - i, state);
       if (r == __MB_ERR_ILLEGAL_SEQUENCE) {
         *src += i;
-        return reset_and_return_illegal(EILSEQ, state);
+        return mbstate_reset_and_return_illegal(EILSEQ, state);
       }
       if (r == __MB_ERR_INCOMPLETE_SEQUENCE) {
         *src += nmc;
-        return reset_and_return(EILSEQ, state);
+        return mbstate_reset_and_return_illegal(EILSEQ, state);
       }
       if (r == 0) {
         *src = NULL;
-        return reset_and_return(o, state);
+        return mbstate_reset_and_return(o, state);
       }
     }
   }
   *src += i;
-  return reset_and_return(o, state);
+  return mbstate_reset_and_return(o, state);
 }
 
 size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps) {
@@ -149,7 +149,7 @@
   mbstate_t* state = (ps == NULL) ? &__private_state : ps;
 
   if (!mbsinit(state)) {
-    return reset_and_return_illegal(EILSEQ, state);
+    return mbstate_reset_and_return_illegal(EILSEQ, state);
   }
 
   char buf[MB_LEN_MAX];
@@ -210,25 +210,3 @@
 size_t wcsrtombs(char* dst, const wchar_t** src, size_t len, mbstate_t* ps) {
   return wcsnrtombs(dst, src, SIZE_MAX, len, ps);
 }
-
-int wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t) {
-  return wcscoll(ws1, ws2);
-}
-
-size_t wcsxfrm_l(wchar_t *dest, const wchar_t *src, size_t n, locale_t) {
-  return wcsxfrm(dest, src, n);
-}
-
-long long wcstoll_l(const wchar_t *nptr, wchar_t **endptr, int base,
-                    locale_t) {
-  return wcstoll(nptr, endptr, base);
-}
-
-unsigned long long wcstoull_l(const wchar_t *nptr, wchar_t **endptr,
-                              int base, locale_t) {
-  return wcstoull(nptr, endptr, base);
-}
-
-long double wcstold_l(const wchar_t *nptr, wchar_t **endptr, locale_t) {
-  return wcstold(nptr, endptr);
-}
diff --git a/libc/bionic/wchar_l.cpp b/libc/bionic/wchar_l.cpp
new file mode 100644
index 0000000..6c39e8d
--- /dev/null
+++ b/libc/bionic/wchar_l.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 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 <wchar.h>
+#include <xlocale.h>
+
+int wcscasecmp_l(const wchar_t* ws1, const wchar_t* ws2, locale_t) {
+  return wcscasecmp(ws1, ws2);
+}
+
+int wcsncasecmp_l(const wchar_t* ws1, const wchar_t* ws2, size_t n, locale_t) {
+  return wcsncasecmp(ws1, ws2, n);
+}
+
+int wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t) {
+  return wcscoll(ws1, ws2);
+}
+
+size_t wcsxfrm_l(wchar_t *dest, const wchar_t *src, size_t n, locale_t) {
+  return wcsxfrm(dest, src, n);
+}
+
+long long wcstoll_l(const wchar_t *nptr, wchar_t **endptr, int base,
+                    locale_t) {
+  return wcstoll(nptr, endptr, base);
+}
+
+unsigned long long wcstoull_l(const wchar_t *nptr, wchar_t **endptr,
+                              int base, locale_t) {
+  return wcstoull(nptr, endptr, base);
+}
+
+long double wcstold_l(const wchar_t *nptr, wchar_t **endptr, locale_t) {
+  return wcstold(nptr, endptr);
+}
diff --git a/libc/private/bionic_mbstate.h b/libc/private/bionic_mbstate.h
index 018b47c..292959a 100644
--- a/libc/private/bionic_mbstate.h
+++ b/libc/private/bionic_mbstate.h
@@ -43,11 +43,31 @@
 #define __MB_IS_ERR(rv) (rv == __MB_ERR_ILLEGAL_SEQUENCE || \
                          rv == __MB_ERR_INCOMPLETE_SEQUENCE)
 
-size_t mbstate_bytes_so_far(const mbstate_t* ps);
-void mbstate_set_byte(mbstate_t* ps, int i, char byte);
-uint8_t mbstate_get_byte(const mbstate_t* ps, int n);
-size_t reset_and_return_illegal(int _errno, mbstate_t* ps);
-size_t reset_and_return(int _return, mbstate_t* ps);
+static inline __wur size_t mbstate_bytes_so_far(const mbstate_t* ps) {
+  return
+      (ps->__seq[2] != 0) ? 3 :
+      (ps->__seq[1] != 0) ? 2 :
+      (ps->__seq[0] != 0) ? 1 : 0;
+}
+
+static inline void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
+  ps->__seq[i] = static_cast<uint8_t>(byte);
+}
+
+static inline __wur uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
+  return ps->__seq[n];
+}
+
+static inline __wur size_t mbstate_reset_and_return_illegal(int _errno, mbstate_t* ps) {
+  errno = _errno;
+  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
+  return __MB_ERR_ILLEGAL_SEQUENCE;
+}
+
+static inline __wur size_t mbstate_reset_and_return(int _return, mbstate_t* ps) {
+  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
+  return _return;
+}
 
 __END_DECLS
 
diff --git a/libc/tools/generate-NOTICE.py b/libc/tools/generate-NOTICE.py
index 6573644..d40891c 100755
--- a/libc/tools/generate-NOTICE.py
+++ b/libc/tools/generate-NOTICE.py
@@ -14,17 +14,33 @@
 import tarfile
 import tempfile
 
-def IsUninteresting(path):
-    path = path.lower()
-    if path.endswith(".mk") or path.endswith(".py") or path.endswith(".pyc") or path.endswith(".txt") or path.endswith(".3") or path.endswith(".swp"):
-        return True
-    if path.endswith("/notice") or path.endswith("/readme") or path.endswith("/caveats"):
-        return True
-    if path.endswith("/tzdata") or path.endswith("/zoneinfo/generate"):
-        return True
-    return False
+VERBOSE = False
 
-def IsAutoGenerated(content):
+def warn(s):
+    sys.stderr.write("warning: %s\n" % s)
+
+def warn_verbose(s):
+    if VERBOSE:
+        warn(s)
+
+def is_interesting(path):
+    path = path.lower()
+    uninteresting_extensions = [
+        ".bp",
+        ".map",
+        ".mk",
+        ".py",
+        ".pyc",
+        ".swp",
+        ".txt",
+    ]
+    if os.path.splitext(path)[1] in uninteresting_extensions:
+        return False
+    if path.endswith("/notice") or path.endswith("/readme"):
+        return False
+    return True
+
+def is_auto_generated(content):
     if "Generated by gensyscalls.py" in content or "generated by genserv.py" in content:
         return True
     if "This header was automatically generated from a Linux kernel header" in content:
@@ -33,7 +49,7 @@
 
 copyrights = set()
 
-def ExtractCopyrightAt(lines, i):
+def extract_copyright_at(lines, i):
     hash = lines[i].startswith("#")
 
     # Do we need to back up to find the start of the copyright header?
@@ -100,13 +116,42 @@
 
     return i
 
-args = sys.argv[1:]
-if len(args) == 0:
-    args = [ "." ]
 
-for arg in args:
-    sys.stderr.write('Searching for source files in "%s"...\n' % arg)
+def do_file(path):
+    with open(path, "r") as the_file:
+        try:
+            content = open(path, "r").read().decode("utf-8")
+        except UnicodeDecodeError:
+            warn("bad UTF-8 in %s" % path)
+            content = open(path, "r").read().decode("iso-8859-1")
 
+    lines = content.split("\n")
+
+    if len(lines) <= 4:
+        warn_verbose("ignoring short file %s" % path)
+        return
+
+    if is_auto_generated(content):
+        warn_verbose("ignoring auto-generated file %s" % path)
+        return
+
+    if not "Copyright" in content:
+        if "public domain" in content.lower():
+            warn("ignoring public domain file %s" % path)
+            return
+        warn('no copyright notice found in "%s" (%d lines)' % (path, len(lines)))
+        return
+
+    # Manually iterate because extract_copyright_at tells us how many lines to skip.
+    i = 0
+    while i < len(lines):
+        if "Copyright" in lines[i] and not "@(#) Copyright" in lines[i]:
+            i = extract_copyright_at(lines, i)
+        else:
+            i += 1
+
+
+def do_dir(path):
     for directory, sub_directories, filenames in os.walk(arg):
         if ".git" in sub_directories:
             sub_directories.remove(".git")
@@ -114,45 +159,24 @@
 
         for filename in sorted(filenames):
             path = os.path.join(directory, filename)
-            if IsUninteresting(path):
-                #print "ignoring uninteresting file %s" % path
-                continue
+            if is_interesting(path):
+                do_file(path)
 
-            try:
-                content = open(path, 'r').read().decode('utf-8')
-            except:
-                sys.stderr.write('warning: bad UTF-8 in %s\n' % path)
-                content = open(path, 'r').read().decode('iso-8859-1')
 
-            lines = content.split("\n")
+args = sys.argv[1:]
+if len(args) == 0:
+    args = [ "." ]
 
-            if len(lines) <= 4:
-                #print "ignoring short file %s" % path
-                continue
-
-            if IsAutoGenerated(content):
-                #print "ignoring auto-generated file %s" % path
-                continue
-
-            if not "Copyright" in content:
-                if "public domain" in content.lower():
-                    #print "ignoring public domain file %s" % path
-                    continue
-                sys.stderr.write('warning: no copyright notice found in "%s" (%d lines)\n' % (path, len(lines)))
-                continue
-
-            i = 0
-            while i < len(lines):
-                if "Copyright" in lines[i] and not "@(#) Copyright" in lines[i]:
-                    i = ExtractCopyrightAt(lines, i)
-                i += 1
-
-            #print path
+for arg in args:
+    if os.path.isdir(arg):
+        do_dir(arg)
+    else:
+        do_file(arg)
 
 for copyright in sorted(copyrights):
-    print copyright.encode('utf-8')
+    print copyright.encode("utf-8")
     print
-    print '-------------------------------------------------------------------'
+    print "-------------------------------------------------------------------"
     print
 
 sys.exit(0)
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index 668f008..292bd97 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -34,11 +34,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -48,4 +52,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -33,11 +33,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index a4c6483..408d4dc 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -33,11 +33,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -33,11 +33,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -33,11 +33,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -33,11 +33,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index 8270fe9..2fe2c7b 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -33,11 +33,15 @@
     dlvsym; # introduced=24
 } LIBC;
 
+LIBC_OMR1 { # future
+  global:
+    __cfi_slowpath; # future
+    __cfi_slowpath_diag; # future
+} LIBC_N;
+
 LIBC_PLATFORM {
   global:
     __cfi_init;
-    __cfi_slowpath;
-    __cfi_slowpath_diag;
     android_dlwarning;
     android_get_application_target_sdk_version;
     android_set_application_target_sdk_version;
@@ -47,4 +51,4 @@
     android_create_namespace;
     android_link_namespaces;
     android_get_exported_namespace;
-} LIBC_N;
+} LIBC_OMR1;
diff --git a/libm/Android.bp b/libm/Android.bp
index 8947f4d..75e8957 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -63,7 +63,6 @@
         "upstream-freebsd/lib/msun/src/e_sinhf.c",
         "upstream-freebsd/lib/msun/src/e_sqrt.c",
         "upstream-freebsd/lib/msun/src/e_sqrtf.c",
-        "upstream-freebsd/lib/msun/src/imprecise.c",
         "upstream-freebsd/lib/msun/src/k_cos.c",
         "upstream-freebsd/lib/msun/src/k_cosf.c",
         "upstream-freebsd/lib/msun/src/k_exp.c",
@@ -209,6 +208,7 @@
         // Functionality not in the BSDs.
         "significandl.c",
         "sincos.c",
+        "fake_long_double.c",
 
         // Modified versions of BSD code.
         "signbit.c",
@@ -218,10 +218,6 @@
     ],
 
     multilib: {
-        lib32: {
-            srcs: ["fake_long_double.c"],
-        },
-
         lib64: {
             srcs: [
                 "upstream-freebsd/lib/msun/src/e_acosl.c",
diff --git a/libm/fake_long_double.c b/libm/fake_long_double.c
index 20148a3..fd983ed 100644
--- a/libm/fake_long_double.c
+++ b/libm/fake_long_double.c
@@ -17,12 +17,11 @@
 #include <float.h>
 #include <math.h>
 
-#ifndef __LP64__
-/*
- * The BSD "long double" functions are broken when sizeof(long double) == sizeof(double).
- * Android works around those cases by replacing the broken functions with our own trivial stubs
- * that call the regular "double" function.
- */
+#if !defined(__LP64__)
+
+// The BSD "long double" functions are broken when sizeof(long double) == sizeof(double).
+// Android works around those cases by replacing the broken functions with our own trivial stubs
+// that call the regular "double" function.
 
 long double copysignl(long double a1, long double a2) { return copysign(a1, a2); }
 long double fmaxl(long double a1, long double a2) { return fmax(a1, a2); }
@@ -40,3 +39,7 @@
 long double roundl(long double a1) { return round(a1); }
 
 #endif // __LP64__
+
+// FreeBSD doesn't have ld128 implementations of powl or tgammal, so both LP32 and LP64 need these.
+long double powl(long double x, long double y) { return pow(x, y); }
+long double tgammal(long double x) { return tgamma(x); }
diff --git a/libm/freebsd-compat.h b/libm/freebsd-compat.h
index a4dd6c2..ee41e45 100644
--- a/libm/freebsd-compat.h
+++ b/libm/freebsd-compat.h
@@ -28,7 +28,15 @@
 
 #define __warn_references(sym,msg) /* ignored */
 
-/* digittoint is in BSD's <ctype.h>. */
+// digittoint is in BSD's <ctype.h>, but not ours, so we have a secret
+// implementation in libm. We reuse parts of libm in the NDK's
+// libandroid_support, where it's a static library, so we want all our
+// "hidden" functions start with a double underscore --- being HIDDEN
+// in the ELF sense is not sufficient.
+#define digittoint __libm_digittoint
 int digittoint(char ch);
 
+// Similarly rename _scan_nan.
+#define _scan_nan __libm_scan_nan
+
 #endif
diff --git a/libm/upstream-freebsd/lib/msun/src/imprecise.c b/libm/upstream-freebsd/lib/msun/src/imprecise.c
deleted file mode 100644
index 08cd239..0000000
--- a/libm/upstream-freebsd/lib/msun/src/imprecise.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*-
- * Copyright (c) 2013 David Chisnall
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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 AUTHOR 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 AUTHOR 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.
- *
- * $FreeBSD$
- */
-
-#include <float.h>
-#include <math.h>
-
-/*
- * If long double is not the same size as double, then these will lose
- * precision and we should emit a warning whenever something links against
- * them.
- */
-#if (LDBL_MANT_DIG > 53)
-#define WARN_IMPRECISE(x) \
-	__warn_references(x, # x " has lower than advertised precision");
-#else
-#define WARN_IMPRECISE(x)
-#endif
-/*
- * Declare the functions as weak variants so that other libraries providing
- * real versions can override them.
- */
-#define	DECLARE_WEAK(x)\
-	__weak_reference(imprecise_## x, x);\
-	WARN_IMPRECISE(x)
-
-long double
-imprecise_powl(long double x, long double y)
-{
-
-	return pow(x, y);
-}
-DECLARE_WEAK(powl);
-
-#define DECLARE_IMPRECISE(f) \
-	long double imprecise_ ## f ## l(long double v) { return f(v); }\
-	DECLARE_WEAK(f ## l)
-
-DECLARE_IMPRECISE(tgamma);
diff --git a/tests/uchar_test.cpp b/tests/uchar_test.cpp
index c887f8a..8b29667 100644
--- a/tests/uchar_test.cpp
+++ b/tests/uchar_test.cpp
@@ -280,7 +280,10 @@
 
   char bytes[MB_LEN_MAX];
 
+  memset(bytes, 1, sizeof(bytes));
   EXPECT_EQ(1U, c32rtomb(bytes, L'\0', NULL));
+  EXPECT_EQ('\0', bytes[0]);
+  EXPECT_EQ('\x01', bytes[1]);
 
   memset(bytes, 0, sizeof(bytes));
   EXPECT_EQ(1U, c32rtomb(bytes, L'h', NULL));
@@ -408,4 +411,3 @@
   GTEST_LOG_(INFO) << "uchar.h is unavailable.\n";
 #endif
 }
-
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 109b92c..a81f112 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -759,6 +759,7 @@
   EXPECT_GT(_POSIX_TZNAME_MAX, 0);
   EXPECT_NE(-1, _POSIX_VDISABLE);
 
+  EXPECT_EQ(_POSIX_VERSION, _POSIX2_VERSION);
   EXPECT_GT(_POSIX2_BC_BASE_MAX, 0);
   EXPECT_GT(_POSIX2_BC_DIM_MAX, 0);
   EXPECT_GT(_POSIX2_BC_SCALE_MAX, 0);
@@ -784,7 +785,6 @@
   EXPECT_EQ(-1, _POSIX_SPAWN);
   EXPECT_EQ(-1, _POSIX_THREAD_ROBUST_PRIO_INHERIT);
 
-  EXPECT_EQ(-1, _POSIX2_VERSION);
   EXPECT_EQ(-1, _POSIX2_CHAR_TERM);
   EXPECT_EQ(-1, _POSIX2_C_DEV);
   EXPECT_EQ(-1, _POSIX2_LOCALEDEF);
diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp
index 830eb70..097647f 100644
--- a/tests/wchar_test.cpp
+++ b/tests/wchar_test.cpp
@@ -445,6 +445,18 @@
   ASSERT_EQ(L'e', dst[1]);
   ASSERT_EQ(L'l', dst[2]);
   ASSERT_EQ(&s[3], src);
+
+  memset(dst, 0, sizeof(dst));
+  const char* incomplete = "\xc2"; // Incomplete UTF-8 sequence.
+  src = incomplete;
+  errno = 0;
+  ASSERT_EQ(static_cast<size_t>(-1), mbsnrtowcs(dst, &src, SIZE_MAX, 3, nullptr));
+  ASSERT_EQ(EILSEQ, errno);
+
+  src = incomplete;
+  errno = 0;
+  ASSERT_EQ(static_cast<size_t>(-1), mbsnrtowcs(nullptr, &src, SIZE_MAX, 3, nullptr));
+  ASSERT_EQ(EILSEQ, errno);
 }
 
 TEST(wchar, wcsftime) {