Merge "Add option to force memunreachable check."
diff --git a/README.md b/README.md
index e67f305..85c8190 100644
--- a/README.md
+++ b/README.md
@@ -211,6 +211,10 @@
      implemented in the kernel. For simple syscalls, that's just the
      auto-generated argument and return value marshalling.
 
+     Add a test in the right file in tests/. We have one file per header, so if
+     your system call is exposed in <unistd.h>, for example, your test would go
+     in tests/unistd_test.cpp.
+
      A trivial test that deliberately supplies an invalid argument helps check
      that we're generating the right symbol and have the right declaration in
      the header file, and that the change to libc.map.txt from step 5 is
@@ -237,6 +241,39 @@
 than 2GiB, say -- so you may end up just writing a "meaningless" program whose
 only purpose is to give you patterns to look for when run under strace(1).)
 
+A general example of adding a system call:
+https://android-review.googlesource.com/c/platform/bionic/+/2073827
+
+### Debugging tips
+1. Key error for a new codename in libc/libc.map.txt
+e.g. what you add in libc/libc.map.txt is:
+
+```
+LIBC_V { # introduced=Vanilla
+  global:
+    xxx; // the new system call you add
+} LIBC_U;
+```
+
+The error output is:
+
+```
+Traceback (most recent call last):
+  File "/path/tp/out/soong/.temp/Soong.python_qucjwd7g/symbolfile/__init__.py", line 171,
+  in decode_api_level_tag
+    decoded = str(decode_api_level(value, api_map))
+  File "/path/to/out/soong/.temp/Soong.python_qucjwd7g/symbolfile/__init__.py", line 157,
+  in decode_api_level
+    return api_map[api]
+KeyError: 'Vanilla'
+```
+
+Solution: Ask in the team and wait for the update.
+
+2. Use of undeclared identifier of the new system call in the test
+Possible Solution: Check everything ready in the files mentioned above first.
+Maybe glibc matters. Follow the example and try #if defined(__GLIBC__).
+
 ## Updating kernel header files
 
 As mentioned above, this is currently a two-step process:
diff --git a/libc/SECCOMP_ALLOWLIST_COMMON.TXT b/libc/SECCOMP_ALLOWLIST_COMMON.TXT
index 0366fdf..a4218ee 100644
--- a/libc/SECCOMP_ALLOWLIST_COMMON.TXT
+++ b/libc/SECCOMP_ALLOWLIST_COMMON.TXT
@@ -76,5 +76,3 @@
 int sched_rr_get_interval_time64(pid_t, timespec64*) lp32
 # Since Linux 5.4, not in glibc. Probed for and conditionally used by ART.
 int userfaultfd(int) all
-# Since Linux 5.9, used by POSIX_SPAWN_CLOEXEC_DEFAULT
-int close_range(unsigned int, unsigned int, int) all
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index a09c614..1435e79 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -107,6 +107,7 @@
 ssize_t     __pwritev64v2:pwritev2(int, const struct iovec*, int, long, long, int) all
 
 int         __close:close(int)  all
+int         close_range(unsigned int, unsigned int, int) all
 pid_t       __getpid:getpid()  all
 int memfd_create(const char*, unsigned) all
 int         munmap(void*, size_t)  all
diff --git a/libc/bionic/heap_tagging.cpp b/libc/bionic/heap_tagging.cpp
index 41aa205..f84ba7b 100644
--- a/libc/bionic/heap_tagging.cpp
+++ b/libc/bionic/heap_tagging.cpp
@@ -72,23 +72,21 @@
 }
 
 static bool set_tcf_on_all_threads(int tcf) {
-  static int g_tcf;
-  g_tcf = tcf;
-
   return android_run_on_all_threads(
-      [](void*) {
+      [](void* arg) {
+        int tcf = *reinterpret_cast<int*>(arg);
         int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
         if (tagged_addr_ctrl < 0) {
           return false;
         }
 
-        tagged_addr_ctrl = (tagged_addr_ctrl & ~PR_MTE_TCF_MASK) | g_tcf;
+        tagged_addr_ctrl = (tagged_addr_ctrl & ~PR_MTE_TCF_MASK) | tcf;
         if (prctl(PR_SET_TAGGED_ADDR_CTRL, tagged_addr_ctrl, 0, 0, 0) < 0) {
           return false;
         }
         return true;
       },
-      nullptr);
+      &tcf);
 }
 
 pthread_mutex_t g_heap_tagging_lock = PTHREAD_MUTEX_INITIALIZER;
diff --git a/libc/bionic/spawn.cpp b/libc/bionic/spawn.cpp
index 59f7631..7e80ef6 100644
--- a/libc/bionic/spawn.cpp
+++ b/libc/bionic/spawn.cpp
@@ -52,7 +52,7 @@
 // mark all open fds except stdin/out/err as close-on-exec
 static int cloexec_except_stdioe() {
   // requires 5.11+ or ACK 5.10-T kernel, otherwise returns ENOSYS or EINVAL
-  if (!syscall(SYS_close_range, 3, ~0U, CLOSE_RANGE_CLOEXEC)) return 0;
+  if (!close_range(3, ~0U, CLOSE_RANGE_CLOEXEC)) return 0;
 
   // unfortunately getrlimit can lie:
   // - both soft and hard limits can be lowered to 0, with fds still open, so it can underestimate
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index e360421..f142525 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -317,6 +317,22 @@
 void swab(const void* __src, void* __dst, ssize_t __byte_count) __INTRODUCED_IN(28);
 #endif
 
+/**
+ * [close_range(2)](https://man7.org/linux/man-pages/man2/close_range.2.html)
+ * performs an action (which depends on value of flags) on an inclusive range
+ * of file descriptors.
+ *
+ * Available since API level 34.
+ *
+ * Note: there is no emulation on too old kernels, hence this will fail with
+ * -1/ENOSYS on pre-5.9 kernels, -1/EINVAL for unsupported flags.  In particular
+ * CLOSE_RANGE_CLOEXEC requires 5.11, though support was backported to Android
+ * Common Kernel 5.10-T.
+ *
+ * Returns 0 on success, and returns -1 and sets `errno` on failure.
+ */
+int close_range(unsigned int __min_fd, unsigned int __max_fd, int __flags) __INTRODUCED_IN(34);
+
 #if defined(__BIONIC_INCLUDE_FORTIFY_HEADERS)
 #define _UNISTD_H_
 #include <bits/fortify/unistd.h>
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 7397b68..e64fe00 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1576,6 +1576,11 @@
     pwritev64v2;
 } LIBC_S;
 
+LIBC_U { # introduced=UpsideDownCake
+  global:
+    close_range;
+} LIBC_T;
+
 LIBC_PRIVATE {
   global:
     __accept4; # arm x86
diff --git a/tests/Android.bp b/tests/Android.bp
index a54ffb8..6a41cf2 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -331,8 +331,8 @@
 cc_test_library {
     name: "clang_diagnostic_tests",
     cflags: [
-      "-Xclang",
-      "-verify",
+        "-Xclang",
+        "-verify",
     ],
     srcs: ["sys_ioctl_diag_test.cpp"],
 }
@@ -641,9 +641,6 @@
     ],
     tidy: false,
     target: {
-        host: {
-            clang_cflags: ["-D__clang__"],
-        },
         musl: {
             // Musl doesn't have fortify
             enabled: false,
@@ -727,7 +724,7 @@
     tidy: false,
     target: {
         host: {
-            clang_cflags: ["-D__clang__"],
+            cflags: ["-D__clang__"],
         },
     },
 }
@@ -762,7 +759,6 @@
     },
 }
 
-
 // -----------------------------------------------------------------------------
 // Library of all tests (excluding the dynamic linker tests).
 // -----------------------------------------------------------------------------
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 6d7e687..293b45a 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -1648,3 +1648,23 @@
   auto t1 = std::chrono::steady_clock::now();
   ASSERT_GE(t1-t0, 1s);
 }
+
+TEST(UNISTD_TEST, close_range) {
+#if defined(__GLIBC__)
+  GTEST_SKIP() << "glibc too old";
+#else   // __GLIBC__
+  int fd = open("/proc/version", O_RDONLY);
+  ASSERT_GE(fd, 0);
+
+  // Try to close the file descriptor (this requires a 5.9+ kernel)
+  if (close_range(fd, fd, 0) == 0) {
+    // we can't close it *again*
+    ASSERT_EQ(close(fd), -1);
+    ASSERT_EQ(errno, EBADF);
+  } else {
+    ASSERT_EQ(errno, ENOSYS);
+    // since close_range() failed, we can close it normally
+    ASSERT_EQ(close(fd), 0);
+  }
+#endif  // __GLIBC__
+}