Merge "Snap for 8018583 from e2c784f15912115f778e427f0ce9a21189a3b494 to ndk-r24-release" into ndk-r24-release
diff --git a/OWNERS b/OWNERS
index 4cb95a3..e02ad9f 100644
--- a/OWNERS
+++ b/OWNERS
@@ -3,9 +3,7 @@
 cferris@google.com
 danalbert@google.com
 hhb@google.com
-jmgao@google.com
 rprichard@google.com
-tomcherry@google.com
 yabinc@google.com
 
 # Still the best reviewer for changes related to the dynamic linker.
diff --git a/benchmarks/time_benchmark.cpp b/benchmarks/time_benchmark.cpp
index 437dc78..a765e3e 100644
--- a/benchmarks/time_benchmark.cpp
+++ b/benchmarks/time_benchmark.cpp
@@ -187,3 +187,13 @@
   }
 }
 BIONIC_BENCHMARK(BM_time_localtime_r);
+
+void BM_time_strftime(benchmark::State& state) {
+  char buf[128];
+  time_t t = 0;
+  struct tm* tm = gmtime(&t);
+  while (state.KeepRunning()) {
+    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm);
+  }
+}
+BIONIC_BENCHMARK(BM_time_strftime);
diff --git a/docs/EINTR.md b/docs/EINTR.md
new file mode 100644
index 0000000..8d1ab52
--- /dev/null
+++ b/docs/EINTR.md
@@ -0,0 +1,91 @@
+# EINTR
+
+## The problem
+
+If your code is blocked in a system call when a signal needs to be delivered,
+the kernel needs to interrupt that system call. For something like a read(2)
+call where some data has already been read, the call can just return with
+what data it has. (This is one reason why read(2) sometimes returns less data
+than you asked for, even though more data is available. It also explains why
+such behavior is relatively rare, and a cause of bugs.)
+
+But what if read(2) hasn't read any data yet? Or what if you've made some other
+system call, for which there is no equivalent "partial" success, such as
+poll(2)? In poll(2)'s case, there's either something to report (in which
+case the system call would already have returned), or there isn't.
+
+The kernel's solution to this problem is to return failure (-1) and set
+errno to `EINTR`: "interrupted system call".
+
+### Can I just opt out?
+
+Technically, yes. In practice on Android, no. Technically if a signal's
+disposition is set to ignore, the kernel doesn't even have to deliver the
+signal, so your code can just stay blocked in the system call it was already
+making. In practice, though, you can't guarantee that all signals are either
+ignored or will kill your process... Unless you're a small single-threaded
+C program that doesn't use any libraries, you can't realistically make this
+guarantee. If any code has installed a signal handler, you need to cope with
+`EINTR`. And if you're an Android app, the zygote has already installed a whole
+host of signal handlers before your code even starts to run. (And, no, you
+can't ignore them instead, because some of them are critical to how ART works.
+For example: Java `NullPointerException`s are optimized by trapping `SIGSEGV`
+signals so that the code generated by the JIT doesn't have to insert explicit
+null pointer checks.)
+
+### Why don't I see this in Java code?
+
+You won't see this in Java because the decision was taken to hide this issue
+from Java programmers. Basically, all the libraries like `java.io.*` and
+`java.net.*` hide this from you. (The same should be true of `android.*` too,
+so it's worth filing bugs if you find any exceptions that aren't documented!)
+
+### Why doesn't libc do that too?
+
+For most people, things would be easier if libc hid this implementation
+detail. But there are legitimate use cases, and automatically retrying
+would hide those. For example, you might want to use signals and `EINTR`
+to interrupt another thread (in fact, that's how interruption of threads
+doing I/O works in Java behind the scenes!). As usual, C/C++ choose the more
+powerful but more error-prone option.
+
+## The fix
+
+### Easy cases
+
+In most cases, the fix is simple: wrap the system call with the
+`TEMP_FAILURE_RETRY` macro. This is basically a while loop that retries the
+system call as long as the result is -1 and errno is `EINTR`.
+
+So, for example:
+```
+  n = read(fd, buf, buf_size); // BAD!
+  n = TEMP_FAILURE_RETRY(read(fd, buf, buf_size)); // GOOD!
+```
+
+### close(2)
+
+TL;DR: *never* wrap close(2) calls with `TEMP_FAILURE_RETRY`.
+
+The case of close(2) is complicated. POSIX explicitly says that close(2)
+shouldn't close the file descriptor if it returns `EINTR`, but that's *not*
+true on Linux (and thus on Android). See
+[Returning EINTR from close()](https://lwn.net/Articles/576478/)
+for more discussion.
+
+Given that most Android code (and especially "all apps") are multithreaded,
+retrying close(2) is especially dangerous because the file descriptor might
+already have been reused by another thread, so the "retry" succeeds, but
+actually closes a *different* file descriptor belonging to a *different*
+thread.
+
+### Timeouts
+
+System calls with timeouts are the other interesting case where "just wrap
+everything with `TEMP_FAILURE_RETRY()`" doesn't work. Because some amount of
+time will have elapsed, you'll want to recalculate the timeout. Otherwise you
+can end up with your 1 minute timeout being indefinite if you're receiving
+signals at least once per minute, say. In this case you'll want to do
+something like adding an explicit loop around your system call, calculating
+the timeout _inside_ the loop, and using `continue` each time the system call
+fails with `EINTR`.
diff --git a/docs/fdsan.md b/docs/fdsan.md
index e0cf80a..6630299 100644
--- a/docs/fdsan.md
+++ b/docs/fdsan.md
@@ -3,6 +3,8 @@
 [TOC]
 
 fdsan is a file descriptor sanitizer added to Android in API level 29.
+In API level 29, fdsan warns when it finds a bug.
+In API level 30, fdsan aborts when it finds a bug.
 
 ### Background
 *What problem is fdsan trying to solve? Why should I care?*
diff --git a/libc/Android.bp b/libc/Android.bp
index 00904aa..2dc10fc 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -67,6 +67,13 @@
 
     // GWP-ASan requires platform TLS.
     "-fno-emulated-tls",
+
+    // We know clang does a lot of harm by rewriting what we've said, and sadly
+    // never see any good it does, so let's just ask it to do what we say...
+    // (The specific motivating example was clang turning a loop that would only
+    // ever touch 0, 1, or 2 bytes into a call to memset, which was never going
+    // to amortize.)
+    "-fno-builtin",
 ]
 
 // Define some common cflags
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 22b82f1..a09c614 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -306,6 +306,8 @@
 int     sysinfo(struct sysinfo*)  all
 int     personality(unsigned long)  all
 
+int     bpf(int, union bpf_attr *, unsigned int) all
+
 ssize_t tee(int, int, size_t, unsigned int)  all
 ssize_t splice(int, off64_t*, int, off64_t*, size_t, unsigned int)  all
 ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int)  all
diff --git a/libc/bionic/c32rtomb.cpp b/libc/bionic/c32rtomb.cpp
index d2519b9..4fa76ff 100644
--- a/libc/bionic/c32rtomb.cpp
+++ b/libc/bionic/c32rtomb.cpp
@@ -66,10 +66,8 @@
   // about the sequence length.
   uint8_t lead;
   size_t length;
-  if ((c32 & ~0x7f) == 0) {
-    lead = 0;
-    length = 1;
-  } else if ((c32 & ~0x7ff) == 0) {
+  // We already handled the 1-byte case above, so we go straight to 2-bytes...
+  if ((c32 & ~0x7ff) == 0) {
     lead = 0xc0;
     length = 2;
   } else if ((c32 & ~0xffff) == 0) {
diff --git a/libc/bionic/mbrtoc32.cpp b/libc/bionic/mbrtoc32.cpp
index 21603a1..d37ca66 100644
--- a/libc/bionic/mbrtoc32.cpp
+++ b/libc/bionic/mbrtoc32.cpp
@@ -80,11 +80,8 @@
   // The first byte in the state (if any) tells the length.
   size_t bytes_so_far = mbstate_bytes_so_far(state);
   ch = bytes_so_far > 0 ? mbstate_get_byte(state, 0) : static_cast<uint8_t>(*s);
-  if ((ch & 0x80) == 0) {
-    mask = 0x7f;
-    length = 1;
-    lower_bound = 0;
-  } else if ((ch & 0xe0) == 0xc0) {
+  // We already handled the 1-byte case above, so we go straight to 2-bytes...
+  if ((ch & 0xe0) == 0xc0) {
     mask = 0x1f;
     length = 2;
     lower_bound = 0x80;
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
index f7beb2c..40786fa 100644
--- a/libc/include/malloc.h
+++ b/libc/include/malloc.h
@@ -97,30 +97,31 @@
  */
 size_t malloc_usable_size(const void* __ptr) __INTRODUCED_IN(17);
 
+#define __MALLINFO_BODY \
+  /** Total number of non-mmapped bytes currently allocated from OS. */ \
+  size_t arena; \
+  /** Number of free chunks. */ \
+  size_t ordblks; \
+  /** (Unused.) */ \
+  size_t smblks; \
+  /** (Unused.) */ \
+  size_t hblks; \
+  /** Total number of bytes in mmapped regions. */ \
+  size_t hblkhd; \
+  /** Maximum total allocated space; greater than total if trimming has occurred. */ \
+  size_t usmblks; \
+  /** (Unused.) */ \
+  size_t fsmblks; \
+  /** Total allocated space (normal or mmapped.) */ \
+  size_t uordblks; \
+  /** Total free space. */ \
+  size_t fordblks; \
+  /** Upper bound on number of bytes releasable by a trim operation. */ \
+  size_t keepcost;
+
 #ifndef STRUCT_MALLINFO_DECLARED
 #define STRUCT_MALLINFO_DECLARED 1
-struct mallinfo {
-  /** Total number of non-mmapped bytes currently allocated from OS. */
-  size_t arena;
-  /** Number of free chunks. */
-  size_t ordblks;
-  /** (Unused.) */
-  size_t smblks;
-  /** (Unused.) */
-  size_t hblks;
-  /** Total number of bytes in mmapped regions. */
-  size_t hblkhd;
-  /** Maximum total allocated space; greater than total if trimming has occurred. */
-  size_t usmblks;
-  /** (Unused.) */
-  size_t fsmblks;
-  /** Total allocated space (normal or mmapped.) */
-  size_t uordblks;
-  /** Total free space. */
-  size_t fordblks;
-  /** Upper bound on number of bytes releasable by a trim operation. */
-  size_t keepcost;
-};
+struct mallinfo { __MALLINFO_BODY };
 #endif
 
 /**
@@ -131,6 +132,18 @@
 struct mallinfo mallinfo(void);
 
 /**
+ * On Android the struct mallinfo and struct mallinfo2 are the same.
+ */
+struct mallinfo2 { __MALLINFO_BODY };
+
+/**
+ * [mallinfo2(3)](http://man7.org/linux/man-pages/man3/mallinfo2.3.html) returns
+ * information about the current state of the heap. Note that mallinfo2() is
+ * inherently unreliable and consider using malloc_info() instead.
+ */
+struct mallinfo2 mallinfo2(void) __RENAME(mallinfo);
+
+/**
  * [malloc_info(3)](http://man7.org/linux/man-pages/man3/malloc_info.3.html)
  * writes information about the current state of the heap to the given stream.
  *
diff --git a/libc/include/sched.h b/libc/include/sched.h
index 3260231..364ca10 100644
--- a/libc/include/sched.h
+++ b/libc/include/sched.h
@@ -26,8 +26,12 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _SCHED_H_
-#define _SCHED_H_
+#pragma once
+
+/**
+ * @file sched.h
+ * @brief Thread execution scheduling.
+ */
 
 #include <bits/timespec.h>
 #include <linux/sched.h>
@@ -35,29 +39,170 @@
 
 __BEGIN_DECLS
 
-/* This name is used by glibc, but not by the kernel. */
+/*
+ * @def SCHED_NORMAL
+ * The standard (as opposed to real-time) round-robin scheduling policy.
+ *
+ * (Linux's name for POSIX's SCHED_OTHER.)
+ *
+ * See [sched(7)](http://man7.org/linux/man-pages/man7/sched.7.html)
+ */
+
+/*
+ * @def SCHED_FIFO
+ * The real-time first-in/first-out scheduling policy.
+ *
+ * See [sched(7)](http://man7.org/linux/man-pages/man7/sched.7.html)
+ */
+
+/*
+ * @def SCHED_RR
+ * The real-time round-robin policy. (See also SCHED_NORMAL/SCHED_OTHER.)
+ *
+ * See [sched(7)](http://man7.org/linux/man-pages/man7/sched.7.html)
+ */
+
+/*
+ * @def SCHED_BATCH
+ * The batch scheduling policy.
+ *
+ * See [sched(7)](http://man7.org/linux/man-pages/man7/sched.7.html)
+ */
+
+/*
+ * @def SCHED_IDLE
+ * The low priority "only when otherwise idle" scheduling priority.
+ *
+ * See [sched(7)](http://man7.org/linux/man-pages/man7/sched.7.html)
+ */
+
+/*
+ * @def SCHED_DEADLINE
+ * The deadline scheduling policy.
+ *
+ * See [sched(7)](http://man7.org/linux/man-pages/man7/sched.7.html)
+ */
+
+/*
+ * The standard (as opposed to real-time) round-robin scheduling policy.
+ *
+ * (POSIX's name for Linux's SCHED_NORMAL.)
+ */
 #define SCHED_OTHER SCHED_NORMAL
 
+/**
+ * See sched_getparam()/sched_setparam() and
+ * sched_getscheduler()/sched_setscheduler().
+ */
 struct sched_param {
   int sched_priority;
 };
 
+/**
+ * [sched_setscheduler(2)](http://man7.org/linux/man-pages/man2/sched_getcpu.2.html)
+ * sets the scheduling policy and associated parameters for the given thread.
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ */
 int sched_setscheduler(pid_t __pid, int __policy, const struct sched_param* __param);
+
+/**
+ * [sched_getscheduler(2)](http://man7.org/linux/man-pages/man2/sched_getcpu.2.html)
+ * gets the scheduling policy for the given thread.
+ *
+ * Returns a non-negative thread policy on success and returns -1 and sets
+ * `errno` on failure.
+ */
 int sched_getscheduler(pid_t __pid);
+
+/**
+ * [sched_yield(2)](http://man7.org/linux/man-pages/man2/sched_yield.2.html)
+ * voluntarily gives up using the CPU so that another thread can run.
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ */
 int sched_yield(void);
+
+/**
+ * [sched_get_priority_max(2)](http://man7.org/linux/man-pages/man2/sched_get_priority_max.2.html)
+ * gets the maximum priority value allowed for the given scheduling policy.
+ *
+ * Returns a priority on success and returns -1 and sets `errno` on failure.
+ */
 int sched_get_priority_max(int __policy);
+
+/**
+ * [sched_get_priority_min(2)](http://man7.org/linux/man-pages/man2/sched_get_priority_min.2.html)
+ * gets the minimum priority value allowed for the given scheduling policy.
+ *
+ * Returns a priority on success and returns -1 and sets `errno` on failure.
+ */
 int sched_get_priority_min(int __policy);
+
+/**
+ * [sched_setparam(2)](http://man7.org/linux/man-pages/man2/sched_setparam.2.html)
+ * sets the scheduling parameters for the given thread.
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ */
 int sched_setparam(pid_t __pid, const struct sched_param* __param);
+
+/**
+ * [sched_getparam(2)](http://man7.org/linux/man-pages/man2/sched_getparam.2.html)
+ * gets the scheduling parameters for the given thread.
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ */
 int sched_getparam(pid_t __pid, struct sched_param* __param);
+
+/**
+ * [sched_rr_get_interval(2)](http://man7.org/linux/man-pages/man2/sched_rr_get_interval.2.html)
+ * queries the round-robin time quantum for the given thread.
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ */
 int sched_rr_get_interval(pid_t __pid, struct timespec* __quantum);
 
 #if defined(__USE_GNU)
 
+/**
+ * [clone(2)](http://man7.org/linux/man-pages/man2/clone.2.html)
+ * creates a new child process.
+ *
+ * Returns the pid of the child to the caller on success and
+ * returns -1 and sets `errno` on failure.
+ */
 int clone(int (*__fn)(void*), void* __child_stack, int __flags, void* __arg, ...) __INTRODUCED_IN_ARM(9) __INTRODUCED_IN_X86(17);
+
+/**
+ * [unshare(2)](http://man7.org/linux/man-pages/man2/unshare.2.html)
+ * disassociates part of the caller's execution context.
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ *
+ * Available since API level 17.
+ */
 int unshare(int __flags) __INTRODUCED_IN(17);
-int sched_getcpu(void);
+
+/**
+ * [setns(2)](http://man7.org/linux/man-pages/man2/setns.2.html)
+ * reassociates a thread with a different namespace.
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ *
+ * Available since API level 21.
+ */
 int setns(int __fd, int __ns_type) __INTRODUCED_IN(21);
 
+/**
+ * [sched_getcpu(3)](http://man7.org/linux/man-pages/man3/sched_getcpu.3.html)
+ * reports which CPU the caller is running on.
+ *
+ * Returns a non-negative CPU number on success and returns -1 and sets
+ * `errno` on failure.
+ */
+int sched_getcpu(void);
+
 #ifdef __LP64__
 #define CPU_SETSIZE 1024
 #else
@@ -69,39 +214,50 @@
 #define __CPU_ELT(x)   ((x) / __CPU_BITS)
 #define __CPU_MASK(x)  ((__CPU_BITTYPE)1 << ((x) & (__CPU_BITS - 1)))
 
+/**
+ * [cpu_set_t](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) is a
+ * statically-sized CPU set. See `CPU_ALLOC` for dynamically-sized CPU sets.
+ */
 typedef struct {
   __CPU_BITTYPE  __bits[ CPU_SETSIZE / __CPU_BITS ];
 } cpu_set_t;
 
+/**
+ * [sched_setaffinity(2)](http://man7.org/linux/man-pages/man2/sched_setaffinity.2.html)
+ * sets the CPU affinity mask for the given thread.
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ */
 int sched_setaffinity(pid_t __pid, size_t __set_size, const cpu_set_t* __set);
+
+/**
+ * [sched_getaffinity(2)](http://man7.org/linux/man-pages/man2/sched_getaffinity.2.html)
+ * gets the CPU affinity mask for the given thread.
+ *
+ * Returns 0 on success and returns -1 and sets `errno` on failure.
+ */
 int sched_getaffinity(pid_t __pid, size_t __set_size, cpu_set_t* __set);
 
+/**
+ * [CPU_ZERO](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) clears all
+ * bits in a static CPU set.
+ */
 #define CPU_ZERO(set)          CPU_ZERO_S(sizeof(cpu_set_t), set)
-#define CPU_SET(cpu, set)      CPU_SET_S(cpu, sizeof(cpu_set_t), set)
-#define CPU_CLR(cpu, set)      CPU_CLR_S(cpu, sizeof(cpu_set_t), set)
-#define CPU_ISSET(cpu, set)    CPU_ISSET_S(cpu, sizeof(cpu_set_t), set)
-#define CPU_COUNT(set)         CPU_COUNT_S(sizeof(cpu_set_t), set)
-#define CPU_EQUAL(set1, set2)  CPU_EQUAL_S(sizeof(cpu_set_t), set1, set2)
-
-#define CPU_AND(dst, set1, set2)  __CPU_OP(dst, set1, set2, &)
-#define CPU_OR(dst, set1, set2)   __CPU_OP(dst, set1, set2, |)
-#define CPU_XOR(dst, set1, set2)  __CPU_OP(dst, set1, set2, ^)
-
-#define __CPU_OP(dst, set1, set2, op)  __CPU_OP_S(sizeof(cpu_set_t), dst, set1, set2, op)
-
-/* Support for dynamically-allocated cpu_set_t */
-
-#define CPU_ALLOC_SIZE(count) \
-  __CPU_ELT((count) + (__CPU_BITS - 1)) * sizeof(__CPU_BITTYPE)
-
-#define CPU_ALLOC(count)  __sched_cpualloc((count))
-#define CPU_FREE(set)     __sched_cpufree((set))
-
-cpu_set_t* __sched_cpualloc(size_t __count);
-void __sched_cpufree(cpu_set_t* __set);
-
+/**
+ * [CPU_ZERO_S](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) clears all
+ * bits in a dynamic CPU set allocated by `CPU_ALLOC`.
+ */
 #define CPU_ZERO_S(setsize, set)  __builtin_memset(set, 0, setsize)
 
+/**
+ * [CPU_SET](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) sets one
+ * bit in a static CPU set.
+ */
+#define CPU_SET(cpu, set)      CPU_SET_S(cpu, sizeof(cpu_set_t), set)
+/**
+ * [CPU_SET_S](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) sets one
+ * bit in a dynamic CPU set allocated by `CPU_ALLOC`.
+ */
 #define CPU_SET_S(cpu, setsize, set) \
   do { \
     size_t __cpu = (cpu); \
@@ -109,6 +265,15 @@
       (set)->__bits[__CPU_ELT(__cpu)] |= __CPU_MASK(__cpu); \
   } while (0)
 
+/**
+ * [CPU_CLR](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) clears one
+ * bit in a static CPU set.
+ */
+#define CPU_CLR(cpu, set)      CPU_CLR_S(cpu, sizeof(cpu_set_t), set)
+/**
+ * [CPU_CLR_S](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) clears one
+ * bit in a dynamic CPU set allocated by `CPU_ALLOC`.
+ */
 #define CPU_CLR_S(cpu, setsize, set) \
   do { \
     size_t __cpu = (cpu); \
@@ -116,6 +281,15 @@
       (set)->__bits[__CPU_ELT(__cpu)] &= ~__CPU_MASK(__cpu); \
   } while (0)
 
+/**
+ * [CPU_ISSET](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) tests
+ * whether the given bit is set in a static CPU set.
+ */
+#define CPU_ISSET(cpu, set)    CPU_ISSET_S(cpu, sizeof(cpu_set_t), set)
+/**
+ * [CPU_ISSET_S](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) tests
+ * whether the given bit is set in a dynamic CPU set allocated by `CPU_ALLOC`.
+ */
 #define CPU_ISSET_S(cpu, setsize, set) \
   (__extension__ ({ \
     size_t __cpu = (cpu); \
@@ -124,12 +298,65 @@
       : 0; \
   }))
 
+/**
+ * [CPU_COUNT](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) counts
+ * how many bits are set in a static CPU set.
+ */
+#define CPU_COUNT(set)         CPU_COUNT_S(sizeof(cpu_set_t), set)
+/**
+ * [CPU_COUNT_S](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) counts
+ * how many bits are set in a dynamic CPU set allocated by `CPU_ALLOC`.
+ */
+#define CPU_COUNT_S(setsize, set)  __sched_cpucount((setsize), (set))
+int __sched_cpucount(size_t __set_size, const cpu_set_t* __set);
+
+/**
+ * [CPU_EQUAL](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) tests
+ * whether two static CPU sets have the same bits set and cleared as each other.
+ */
+#define CPU_EQUAL(set1, set2)  CPU_EQUAL_S(sizeof(cpu_set_t), set1, set2)
+/**
+ * [CPU_EQUAL_S](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) tests
+ * whether two dynamic CPU sets allocated by `CPU_ALLOC` have the same bits
+ * set and cleared as each other.
+ */
 #define CPU_EQUAL_S(setsize, set1, set2)  (__builtin_memcmp(set1, set2, setsize) == 0)
 
+/**
+ * [CPU_AND](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) ands two
+ * static CPU sets.
+ */
+#define CPU_AND(dst, set1, set2)  __CPU_OP(dst, set1, set2, &)
+/**
+ * [CPU_AND_S](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) ands two
+ * dynamic CPU sets allocated by `CPU_ALLOC`.
+ */
 #define CPU_AND_S(setsize, dst, set1, set2)  __CPU_OP_S(setsize, dst, set1, set2, &)
+
+/**
+ * [CPU_OR](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) ors two
+ * static CPU sets.
+ */
+#define CPU_OR(dst, set1, set2)   __CPU_OP(dst, set1, set2, |)
+/**
+ * [CPU_OR_S](https://man7.org/linux/man-pages/man3/CPU_SET.3.html) ors two
+ * dynamic CPU sets allocated by `CPU_ALLOC`.
+ */
 #define CPU_OR_S(setsize, dst, set1, set2)   __CPU_OP_S(setsize, dst, set1, set2, |)
+
+/**
+ * [CPU_XOR](https://man7.org/linux/man-pages/man3/CPU_SET.3.html)
+ * exclusive-ors two static CPU sets.
+ */
+#define CPU_XOR(dst, set1, set2)  __CPU_OP(dst, set1, set2, ^)
+/**
+ * [CPU_XOR_S](https://man7.org/linux/man-pages/man3/CPU_SET.3.html)
+ * exclusive-ors two dynamic CPU sets allocated by `CPU_ALLOC`.
+ */
 #define CPU_XOR_S(setsize, dst, set1, set2)  __CPU_OP_S(setsize, dst, set1, set2, ^)
 
+#define __CPU_OP(dst, set1, set2, op)  __CPU_OP_S(sizeof(cpu_set_t), dst, set1, set2, op)
+
 #define __CPU_OP_S(setsize, dstset, srcset1, srcset2, op) \
   do { \
     cpu_set_t* __dst = (dstset); \
@@ -140,12 +367,27 @@
       (__dst)->__bits[__nn] = __src1[__nn] op __src2[__nn]; \
   } while (0)
 
-#define CPU_COUNT_S(setsize, set)  __sched_cpucount((setsize), (set))
+/**
+ * [CPU_ALLOC_SIZE](https://man7.org/linux/man-pages/man3/CPU_SET.3.html)
+ * returns the size of a CPU set large enough for CPUs in the range 0..count-1.
+ */
+#define CPU_ALLOC_SIZE(count) \
+  __CPU_ELT((count) + (__CPU_BITS - 1)) * sizeof(__CPU_BITTYPE)
 
-int __sched_cpucount(size_t __set_size, const cpu_set_t* __set);
+/**
+ * [CPU_ALLOC](https://man7.org/linux/man-pages/man3/CPU_SET.3.html)
+ * allocates a CPU set large enough for CPUs in the range 0..count-1.
+ */
+#define CPU_ALLOC(count)  __sched_cpualloc((count))
+cpu_set_t* __sched_cpualloc(size_t __count);
+
+/**
+ * [CPU_FREE](https://man7.org/linux/man-pages/man3/CPU_SET.3.html)
+ * deallocates a CPU set allocated by `CPU_ALLOC`.
+ */
+#define CPU_FREE(set)     __sched_cpufree((set))
+void __sched_cpufree(cpu_set_t* __set);
 
 #endif /* __USE_GNU */
 
 __END_DECLS
-
-#endif /* _SCHED_H_ */
diff --git a/libc/tzcode/strftime.c b/libc/tzcode/strftime.c
index c05f6b5..7c4be49 100644
--- a/libc/tzcode/strftime.c
+++ b/libc/tzcode/strftime.c
@@ -252,8 +252,8 @@
                                 pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
                 continue;
             case 'd':
-                                pt = _conv(t->tm_mday, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
-                continue;
+              pt = _conv(t->tm_mday, getformat(modifier, "02", " 2", "  ", "02"), pt, ptlim);
+              continue;
             case 'E':
             case 'O':
                 /*
@@ -274,22 +274,21 @@
                 modifier = *format;
                 goto label;
             case 'e':
-                pt = _conv(t->tm_mday, getformat(modifier, "%2d", "%2d", "%d", "%02d"), pt, ptlim);
-                continue;
+              pt = _conv(t->tm_mday, getformat(modifier, " 2", " 2", "  ", "02"), pt, ptlim);
+              continue;
             case 'F':
                 pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
                 continue;
             case 'H':
-                pt = _conv(t->tm_hour, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
-                continue;
+              pt = _conv(t->tm_hour, getformat(modifier, "02", " 2", "  ", "02"), pt, ptlim);
+              continue;
             case 'I':
-                pt = _conv((t->tm_hour % 12) ?
-                    (t->tm_hour % 12) : 12,
-                    getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
-                continue;
+              pt = _conv((t->tm_hour % 12) ? (t->tm_hour % 12) : 12,
+                         getformat(modifier, "02", " 2", "  ", "02"), pt, ptlim);
+              continue;
             case 'j':
-                pt = _conv(t->tm_yday + 1, getformat(modifier, "%03d", "%3d", "%d", "%03d"), pt, ptlim);
-                continue;
+              pt = _conv(t->tm_yday + 1, getformat(modifier, "03", " 3", "  ", "03"), pt, ptlim);
+              continue;
             case 'k':
                 /*
                 ** This used to be...
@@ -301,7 +300,7 @@
                 ** "%l" have been swapped.
                 ** (ado, 1993-05-24)
                 */
-                pt = _conv(t->tm_hour, getformat(modifier, "%2d", "%2d", "%d", "%02d"), pt, ptlim);
+                pt = _conv(t->tm_hour, getformat(modifier, " 2", " 2", "  ", "02"), pt, ptlim);
                 continue;
 #ifdef KITCHEN_SINK
             case 'K':
@@ -321,16 +320,15 @@
                 ** "%l" have been swapped.
                 ** (ado, 1993-05-24)
                 */
-                pt = _conv((t->tm_hour % 12) ?
-                    (t->tm_hour % 12) : 12,
-                    getformat(modifier, "%2d", "%2d", "%d", "%02d"), pt, ptlim);
+                pt = _conv((t->tm_hour % 12) ? (t->tm_hour % 12) : 12,
+                           getformat(modifier, " 2", " 2", "  ", "02"), pt, ptlim);
                 continue;
             case 'M':
-                pt = _conv(t->tm_min, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
-                continue;
+              pt = _conv(t->tm_min, getformat(modifier, "02", " 2", "  ", "02"), pt, ptlim);
+              continue;
             case 'm':
-                pt = _conv(t->tm_mon + 1, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
-                continue;
+              pt = _conv(t->tm_mon + 1, getformat(modifier, "02", " 2", "  ", "02"), pt, ptlim);
+              continue;
             case 'n':
                 pt = _add("\n", pt, ptlim, modifier);
                 continue;
@@ -348,13 +346,12 @@
                 pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp);
                 continue;
             case 'S':
-                pt = _conv(t->tm_sec, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
-                continue;
+              pt = _conv(t->tm_sec, getformat(modifier, "02", " 2", "  ", "02"), pt, ptlim);
+              continue;
             case 's':
                 {
                     struct tm   tm;
-                    char        buf[INT_STRLEN_MAXIMUM(
-                                time64_t) + 1];
+                    char buf[INT_STRLEN_MAXIMUM(time64_t) + 1] __attribute__((__uninitialized__));
                     time64_t    mkt;
 
                     tm = *t;
@@ -374,10 +371,9 @@
                 pt = _add("\t", pt, ptlim, modifier);
                 continue;
             case 'U':
-                pt = _conv((t->tm_yday + DAYSPERWEEK -
-                    t->tm_wday) / DAYSPERWEEK,
-                    getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
-                continue;
+              pt = _conv((t->tm_yday + DAYSPERWEEK - t->tm_wday) / DAYSPERWEEK,
+                         getformat(modifier, "02", " 2", "  ", "02"), pt, ptlim);
+              continue;
             case 'u':
                 /*
                 ** From Arnold Robbins' strftime version 3.0:
@@ -385,9 +381,7 @@
                 ** [1 (Monday) - 7]"
                 ** (ado, 1993-05-24)
                 */
-                pt = _conv((t->tm_wday == 0) ?
-                    DAYSPERWEEK : t->tm_wday,
-                    "%d", pt, ptlim);
+                pt = _conv((t->tm_wday == 0) ? DAYSPERWEEK : t->tm_wday, "  ", pt, ptlim);
                 continue;
             case 'V':   /* ISO 8601 week number */
             case 'G':   /* ISO 8601 year (four digits) */
@@ -467,8 +461,7 @@
                             w = 53;
 #endif /* defined XPG4_1994_04_09 */
                     if (*format == 'V')
-                        pt = _conv(w, getformat(modifier, "%02d", "%2d", "%d", "%02d"),
-                               pt, ptlim);
+                      pt = _conv(w, getformat(modifier, "02", " 2", "  ", "02"), pt, ptlim);
                     else if (*format == 'g') {
                         *warnp = IN_ALL;
                         pt = _yconv(year, base,
@@ -488,15 +481,14 @@
                 pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
                 continue;
             case 'W':
-                pt = _conv((t->tm_yday + DAYSPERWEEK -
-                    (t->tm_wday ?
-                    (t->tm_wday - 1) :
-                    (DAYSPERWEEK - 1))) / DAYSPERWEEK,
-                    getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
-                continue;
+              pt = _conv(
+                  (t->tm_yday + DAYSPERWEEK - (t->tm_wday ? (t->tm_wday - 1) : (DAYSPERWEEK - 1))) /
+                      DAYSPERWEEK,
+                  getformat(modifier, "02", " 2", "  ", "02"), pt, ptlim);
+              continue;
             case 'w':
-                pt = _conv(t->tm_wday, "%d", pt, ptlim);
-                continue;
+              pt = _conv(t->tm_wday, "  ", pt, ptlim);
+              continue;
             case 'X':
                 pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp);
                 continue;
@@ -602,7 +594,7 @@
                 diff /= SECSPERMIN;
                 diff = (diff / MINSPERHOUR) * 100 +
                     (diff % MINSPERHOUR);
-                pt = _conv(diff, getformat(modifier, "%04d", "%4d", "%d", "%04d"), pt, ptlim);
+                pt = _conv(diff, getformat(modifier, "04", " 4", "  ", "04"), pt, ptlim);
                 }
                 continue;
             case '+':
@@ -629,10 +621,40 @@
 static char *
 _conv(int n, const char *format, char *pt, const char *ptlim)
 {
-	char	buf[INT_STRLEN_MAXIMUM(int) + 1];
+  // The original implementation used snprintf(3) here, but rolling our own is
+  // about 5x faster. Seems like a good trade-off for so little code, especially
+  // for users like logcat that have a habit of formatting 10k times all at
+  // once...
 
-	snprintf(buf, sizeof(buf), format, n);
-	return _add(buf, pt, ptlim, 0);
+  // Format is '0' or ' ' for the fill character, followed by a single-digit
+  // width or ' ' for "whatever".
+  //   %d -> "  "
+  //  %2d -> " 2"
+  // %02d -> "02"
+  char fill = format[0];
+  int width = format[1] == ' ' ? 0 : format[1] - '0';
+
+  char buf[32] __attribute__((__uninitialized__));
+
+  // Terminate first, so we can walk backwards from the least-significant digit
+  // without having to later reverse the result.
+  char* p = &buf[31];
+  *--p = '\0';
+  char* end = p;
+
+  // Output digits backwards, from least-significant to most.
+  while (n >= 10) {
+    *--p = '0' + (n % 10);
+    n /= 10;
+  }
+  *--p = '0' + n;
+
+  // Fill if more digits are required by the format.
+  while ((end - p) < width) {
+    *--p = fill;
+  }
+
+  return _add(p, pt, ptlim, 0);
 }
 
 static char *
@@ -704,9 +726,11 @@
     if (convert_top) {
         if (lead == 0 && trail < 0)
             pt = _add("-0", pt, ptlim, modifier);
-        else    pt = _conv(lead, getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
+        else
+          pt = _conv(lead, getformat(modifier, "02", " 2", "  ", "02"), pt, ptlim);
     }
     if (convert_yy)
-        pt = _conv(((trail < 0) ? -trail : trail), getformat(modifier, "%02d", "%2d", "%d", "%02d"), pt, ptlim);
+      pt = _conv(((trail < 0) ? -trail : trail), getformat(modifier, "02", " 2", "  ", "02"), pt,
+                 ptlim);
     return pt;
 }
diff --git a/libm/Android.bp b/libm/Android.bp
index b6ad356..83f40c2 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -490,6 +490,7 @@
         "-DFLT_EVAL_METHOD=0",
         "-include freebsd-compat.h",
         "-include fenv-access.h",
+        "-fno-builtin",
         "-fno-math-errno",
         "-Wall",
         "-Werror",
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp
index 5e8fb9f..8272d39 100644
--- a/tests/malloc_test.cpp
+++ b/tests/malloc_test.cpp
@@ -809,6 +809,77 @@
 #endif
 }
 
+TEST(malloc, mallinfo2) {
+#if defined(__BIONIC__)
+  SKIP_WITH_HWASAN << "hwasan does not implement mallinfo2";
+  static size_t sizes[] = {8, 32, 128, 4096, 32768, 131072, 1024000, 10240000, 20480000, 300000000};
+
+  constexpr static size_t kMaxAllocs = 50;
+
+  for (size_t size : sizes) {
+    // If some of these allocations are stuck in a thread cache, then keep
+    // looping until we make an allocation that changes the total size of the
+    // memory allocated.
+    // jemalloc implementations counts the thread cache allocations against
+    // total memory allocated.
+    void* ptrs[kMaxAllocs] = {};
+    bool pass = false;
+    for (size_t i = 0; i < kMaxAllocs; i++) {
+      struct mallinfo info = mallinfo();
+      struct mallinfo2 info2 = mallinfo2();
+      // Verify that mallinfo and mallinfo2 are exactly the same.
+      ASSERT_EQ(info.arena, info2.arena);
+      ASSERT_EQ(info.ordblks, info2.ordblks);
+      ASSERT_EQ(info.smblks, info2.smblks);
+      ASSERT_EQ(info.hblks, info2.hblks);
+      ASSERT_EQ(info.hblkhd, info2.hblkhd);
+      ASSERT_EQ(info.usmblks, info2.usmblks);
+      ASSERT_EQ(info.fsmblks, info2.fsmblks);
+      ASSERT_EQ(info.uordblks, info2.uordblks);
+      ASSERT_EQ(info.fordblks, info2.fordblks);
+      ASSERT_EQ(info.keepcost, info2.keepcost);
+
+      size_t allocated = info2.uordblks;
+      ptrs[i] = malloc(size);
+      ASSERT_TRUE(ptrs[i] != nullptr);
+
+      info = mallinfo();
+      info2 = mallinfo2();
+      // Verify that mallinfo and mallinfo2 are exactly the same.
+      ASSERT_EQ(info.arena, info2.arena);
+      ASSERT_EQ(info.ordblks, info2.ordblks);
+      ASSERT_EQ(info.smblks, info2.smblks);
+      ASSERT_EQ(info.hblks, info2.hblks);
+      ASSERT_EQ(info.hblkhd, info2.hblkhd);
+      ASSERT_EQ(info.usmblks, info2.usmblks);
+      ASSERT_EQ(info.fsmblks, info2.fsmblks);
+      ASSERT_EQ(info.uordblks, info2.uordblks);
+      ASSERT_EQ(info.fordblks, info2.fordblks);
+      ASSERT_EQ(info.keepcost, info2.keepcost);
+
+      size_t new_allocated = info2.uordblks;
+      if (allocated != new_allocated) {
+        size_t usable_size = malloc_usable_size(ptrs[i]);
+        // Only check if the total got bigger by at least allocation size.
+        // Sometimes the mallinfo2 numbers can go backwards due to compaction
+        // and/or freeing of cached data.
+        if (new_allocated >= allocated + usable_size) {
+          pass = true;
+          break;
+        }
+      }
+    }
+    for (void* ptr : ptrs) {
+      free(ptr);
+    }
+    ASSERT_TRUE(pass) << "For size " << size << " allocated bytes did not increase after "
+                      << kMaxAllocs << " allocations.";
+  }
+#else
+  GTEST_SKIP() << "glibc is broken";
+#endif
+}
+
 template <typename Type>
 void __attribute__((optnone)) VerifyAlignment(Type* floating) {
   size_t expected_alignment = alignof(Type);
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index e4f9cb8..907a35c 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -1493,6 +1493,7 @@
   };
   std::atomic<Progress> progress;
   pthread_t thread;
+  timespec ts;
   std::function<int (pthread_cond_t* cond, pthread_mutex_t* mutex)> wait_function;
 
  protected:
@@ -1524,11 +1525,10 @@
       clockid_t clock,
       std::function<int(pthread_cond_t* cond, pthread_mutex_t* mutex, const timespec* timeout)>
           wait_function) {
-    timespec ts;
     ASSERT_EQ(0, clock_gettime(clock, &ts));
     ts.tv_sec += 1;
 
-    StartWaitingThread([&wait_function, &ts](pthread_cond_t* cond, pthread_mutex_t* mutex) {
+    StartWaitingThread([&wait_function, this](pthread_cond_t* cond, pthread_mutex_t* mutex) {
       return wait_function(cond, mutex, &ts);
     });
 
diff --git a/tests/sys_ttydefaults_test.cpp b/tests/sys_ttydefaults_test.cpp
index fa4f7c7..73aa448 100644
--- a/tests/sys_ttydefaults_test.cpp
+++ b/tests/sys_ttydefaults_test.cpp
@@ -20,7 +20,7 @@
 #include <termios.h>
 
 TEST(sys_ttydefaults, flags) {
-  int i;
+  [[maybe_unused]] int i;
   i = TTYDEF_IFLAG;
   i = TTYDEF_OFLAG;
   i = TTYDEF_LFLAG;
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 840dad0..c306a08 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -688,9 +688,9 @@
 __attribute__((noinline)) static void HwasanReadMemory(const char* p, size_t size) {
   // Read memory byte-by-byte. This will blow up if the pointer tag in p does not match any memory
   // tag in [p, p+size).
-  volatile char z;
+  char z;
   for (size_t i = 0; i < size; ++i) {
-    z = p[i];
+    DoNotOptimize(z = p[i]);
   }
 }
 
diff --git a/tools/versioner/src/Android.bp b/tools/versioner/src/Android.bp
index 0173c41..abcaaa3 100644
--- a/tools/versioner/src/Android.bp
+++ b/tools/versioner/src/Android.bp
@@ -21,8 +21,7 @@
     ],
 
     shared_libs: [
-        "libclang_cxx_host",
-        "libLLVM_host",
+        "libclang-cpp_host",
         "libbase",
     ],