Merge "Allow invoking the linker on an executable."
diff --git a/libc/bionic/poll.cpp b/libc/bionic/poll.cpp
index 3df8b18..41b2657 100644
--- a/libc/bionic/poll.cpp
+++ b/libc/bionic/poll.cpp
@@ -71,7 +71,7 @@
   sigset64_t mutable_ss;
   sigset64_t* mutable_ss_ptr = nullptr;
   if (ss != nullptr) {
-    mutable_ss = filter_reserved_signals(*ss);
+    mutable_ss = filter_reserved_signals(*ss, SIG_SETMASK);
     mutable_ss_ptr = &mutable_ss;
   }
 
@@ -121,7 +121,7 @@
   sigset64_t mutable_ss;
   sigset64_t* mutable_ss_ptr = nullptr;
   if (ss != nullptr) {
-    mutable_ss = filter_reserved_signals(*ss);
+    mutable_ss = filter_reserved_signals(*ss, SIG_SETMASK);
     mutable_ss_ptr = &mutable_ss;
   }
 
diff --git a/libc/bionic/sigaction.cpp b/libc/bionic/sigaction.cpp
index fb57d1c..42dcccd 100644
--- a/libc/bionic/sigaction.cpp
+++ b/libc/bionic/sigaction.cpp
@@ -43,7 +43,7 @@
   if (bionic_new_action != nullptr) {
     kernel_new_action.sa_flags = bionic_new_action->sa_flags;
     kernel_new_action.sa_handler = bionic_new_action->sa_handler;
-    kernel_new_action.sa_mask = filter_reserved_signals(bionic_new_action->sa_mask);
+    kernel_new_action.sa_mask = filter_reserved_signals(bionic_new_action->sa_mask, SIG_SETMASK);
 #if defined(SA_RESTORER)
     kernel_new_action.sa_restorer = bionic_new_action->sa_restorer;
 #if defined(__aarch64__)
@@ -122,7 +122,7 @@
       kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
     }
 #endif
-    kernel_new.sa_mask = filter_reserved_signals(kernel_new.sa_mask);
+    kernel_new.sa_mask = filter_reserved_signals(kernel_new.sa_mask, SIG_SETMASK);
   }
 
   return __rt_sigaction(signal,
diff --git a/libc/bionic/signal.cpp b/libc/bionic/signal.cpp
index 175182b..d6be09a 100644
--- a/libc/bionic/signal.cpp
+++ b/libc/bionic/signal.cpp
@@ -263,7 +263,7 @@
   sigset64_t mutable_set;
   sigset64_t* mutable_set_ptr = nullptr;
   if (set) {
-    mutable_set = filter_reserved_signals(*set);
+    mutable_set = filter_reserved_signals(*set, SIG_SETMASK);
     mutable_set_ptr = &mutable_set;
   }
   return __rt_sigsuspend(mutable_set_ptr, sizeof(*set));
@@ -279,7 +279,7 @@
   sigset64_t mutable_set;
   sigset64_t* mutable_set_ptr = nullptr;
   if (set) {
-    mutable_set = filter_reserved_signals(*set);
+    mutable_set = filter_reserved_signals(*set, SIG_SETMASK);
     mutable_set_ptr = &mutable_set;
   }
   return __rt_sigtimedwait(mutable_set_ptr, info, timeout, sizeof(*set));
diff --git a/libc/bionic/sigprocmask.cpp b/libc/bionic/sigprocmask.cpp
index 36866f3..5f70f32 100644
--- a/libc/bionic/sigprocmask.cpp
+++ b/libc/bionic/sigprocmask.cpp
@@ -26,6 +26,7 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <signal.h>
 
 #include "private/sigrtmin.h"
@@ -65,10 +66,16 @@
 int sigprocmask64(int how,
                   const sigset64_t* new_set,
                   sigset64_t* old_set) __attribute__((__noinline__)) {
+  // how is only checked for validity if new_set is provided.
+  if (new_set && how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK) {
+    errno = EINVAL;
+    return -1;
+  }
+
   sigset64_t mutable_new_set;
   sigset64_t* mutable_new_set_ptr = nullptr;
   if (new_set) {
-    mutable_new_set = filter_reserved_signals(*new_set);
+    mutable_new_set = filter_reserved_signals(*new_set, how);
     mutable_new_set_ptr = &mutable_new_set;
   }
   return __rt_sigprocmask(how, mutable_new_set_ptr, old_set, sizeof(*new_set));
diff --git a/libc/include/bits/sysconf.h b/libc/include/bits/sysconf.h
index 2cbbb11..8607adf 100644
--- a/libc/include/bits/sysconf.h
+++ b/libc/include/bits/sysconf.h
@@ -73,6 +73,7 @@
 #define _SC_XOPEN_LEGACY        0x0024
 #define _SC_ATEXIT_MAX          0x0025
 #define _SC_IOV_MAX             0x0026
+#define _SC_UIO_MAXIOV _SC_IOV_MAX
 #define _SC_PAGESIZE            0x0027
 #define _SC_PAGE_SIZE           0x0028
 #define _SC_XOPEN_UNIX          0x0029
diff --git a/libc/private/sigrtmin.h b/libc/private/sigrtmin.h
index ea8673d..431a1dd 100644
--- a/libc/private/sigrtmin.h
+++ b/libc/private/sigrtmin.h
@@ -32,6 +32,8 @@
 
 #include <signal.h>
 
+#include "bionic_macros.h"
+
 // Realtime signals reserved for internal use:
 //   32 (__SIGRTMIN + 0)        POSIX timers
 //   33 (__SIGRTMIN + 1)        libbacktrace
@@ -42,9 +44,29 @@
 // in <android/legacy_signal_inlines.h> to match.
 
 #define __SIGRT_RESERVED 4
-static inline __always_inline sigset64_t filter_reserved_signals(sigset64_t sigset) {
-  for (int signo = __SIGRTMIN; signo < __SIGRTMIN + __SIGRT_RESERVED; ++signo) {
-    sigdelset64(&sigset, signo);
+static inline __always_inline sigset64_t filter_reserved_signals(sigset64_t sigset, int how) {
+  int (*block)(sigset64_t*, int);
+  int (*unblock)(sigset64_t*, int);
+  switch (how) {
+    case SIG_BLOCK:
+      __BIONIC_FALLTHROUGH;
+    case SIG_SETMASK:
+      block = sigaddset64;
+      unblock = sigdelset64;
+      break;
+
+    case SIG_UNBLOCK:
+      block = sigdelset64;
+      unblock = sigaddset64;
+      break;
   }
+
+  // The POSIX timer signal must be blocked.
+  block(&sigset, __SIGRTMIN + 0);
+
+  // Everything else must remain unblocked.
+  unblock(&sigset, __SIGRTMIN + 1);
+  unblock(&sigset, __SIGRTMIN + 2);
+  unblock(&sigset, __SIGRTMIN + 3);
   return sigset;
 }
diff --git a/tests/SignalUtils.h b/tests/SignalUtils.h
index ece28ba..a2faf0a 100644
--- a/tests/SignalUtils.h
+++ b/tests/SignalUtils.h
@@ -55,3 +55,12 @@
  private:
   sigset64_t old_mask_;
 };
+
+// uint64_t equivalents of sigsetops.
+static inline void SignalSetAdd(uint64_t* sigset, int signo) {
+  *sigset |= 1ULL << (signo - 1);
+}
+
+static inline void SignalSetDel(uint64_t* sigset, int signo) {
+  *sigset &= ~(1ULL << (signo - 1));
+}
diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp
index 05339a6..dde0be1 100644
--- a/tests/setjmp_test.cpp
+++ b/tests/setjmp_test.cpp
@@ -74,6 +74,8 @@
     sigset64_t ss;
     sigemptyset64(&ss);
     sigaddset64(&ss, SIGUSR1 + offset);
+    // TIMER_SIGNAL.
+    sigaddset64(&ss, __SIGRTMIN);
     sigaddset64(&ss, SIGRTMIN + offset);
     return ss;
   }
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index 52a097b..dd27aef 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -22,6 +22,7 @@
 
 #include <thread>
 
+#include <android-base/macros.h>
 #include <gtest/gtest.h>
 
 #include "SignalUtils.h"
@@ -339,6 +340,17 @@
 
 static void ClearSignalMask() {
   uint64_t sigset = 0;
+  SignalSetAdd(&sigset, __SIGRTMIN);
+  if (syscall(__NR_rt_sigprocmask, SIG_SETMASK, &sigset, nullptr, sizeof(sigset)) != 0) {
+    abort();
+  }
+}
+
+static void FillSignalMask() {
+  uint64_t sigset = ~0ULL;
+  for (int signo = __SIGRTMIN + 1; signo < SIGRTMIN; ++signo) {
+    SignalSetDel(&sigset, signo);
+  }
   if (syscall(__NR_rt_sigprocmask, SIG_SETMASK, &sigset, nullptr, sizeof(sigset)) != 0) {
     abort();
   }
@@ -352,40 +364,27 @@
   return sigset;
 }
 
-enum class SignalMaskFunctionType {
-  RtAware,
-  RtNonaware,
-};
-
-#if defined(__LP64__) || !defined(__BIONIC__)
-constexpr SignalMaskFunctionType sigset_type = SignalMaskFunctionType::RtAware;
-#else
-constexpr SignalMaskFunctionType sigset_type = SignalMaskFunctionType::RtNonaware;
-#endif
-
-static void TestSignalMaskFiltered(uint64_t sigset, SignalMaskFunctionType type) {
-  for (int signo = 1; signo <= 64; ++signo) {
+static void TestSignalMaskFiltered(uint64_t sigset) {
+#if defined(__BIONIC__)
+  for (int signo = __SIGRTMIN; signo < SIGRTMIN; ++signo) {
     bool signal_blocked = sigset & (1ULL << (signo - 1));
-    if (signo == SIGKILL || signo == SIGSTOP) {
-      // SIGKILL and SIGSTOP shouldn't be blocked.
-      EXPECT_EQ(false, signal_blocked) << "signal " << signo;
-    } else if (signo < __SIGRTMIN) {
-      // Everything else should be blocked.
+    if (signo == __SIGRTMIN) {
+      // TIMER_SIGNAL must be blocked.
       EXPECT_EQ(true, signal_blocked) << "signal " << signo;
-    } else if (signo >= __SIGRTMIN && signo < SIGRTMIN) {
-      // Reserved signals must not be blocked.
+    } else {
+      // The other reserved signals must not be blocked.
       EXPECT_EQ(false, signal_blocked) << "signal " << signo;
-    } else if (type == SignalMaskFunctionType::RtAware) {
-      // Realtime signals should be blocked, unless we blocked using a non-rt aware function.
-      EXPECT_EQ(true, signal_blocked) << "signal " << signo;
     }
   }
+#else
+  UNUSED(sigset);
+#endif
 }
 
-static void TestSignalMaskFunction(std::function<void()> fn, SignalMaskFunctionType fn_type) {
+static void TestSignalMaskFunction(std::function<void()> fn) {
   ClearSignalMask();
   fn();
-  TestSignalMaskFiltered(GetSignalMask(), fn_type);
+  TestSignalMaskFiltered(GetSignalMask());
 }
 
 TEST(signal, sigaction_filter) {
@@ -397,7 +396,7 @@
   sigaction(SIGUSR1, &sa, nullptr);
   raise(SIGUSR1);
   ASSERT_NE(0ULL, sigset);
-  TestSignalMaskFiltered(sigset, sigset_type);
+  TestSignalMaskFiltered(sigset);
 }
 
 TEST(signal, sigaction64_filter) {
@@ -409,111 +408,135 @@
   sigaction64(SIGUSR1, &sa, nullptr);
   raise(SIGUSR1);
   ASSERT_NE(0ULL, sigset);
-  TestSignalMaskFiltered(sigset, SignalMaskFunctionType::RtAware);
+  TestSignalMaskFiltered(sigset);
 }
 
 TEST(signal, sigprocmask_setmask_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset_t sigset_libc;
-        sigfillset(&sigset_libc);
-        ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &sigset_libc, nullptr));
-      },
-      sigset_type);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset_t sigset_libc;
+    sigfillset(&sigset_libc);
+    ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, sigprocmask64_setmask_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset64_t sigset_libc;
-        sigfillset64(&sigset_libc);
-        ASSERT_EQ(0, sigprocmask64(SIG_SETMASK, &sigset_libc, nullptr));
-      },
-      SignalMaskFunctionType::RtAware);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset64_t sigset_libc;
+    sigfillset64(&sigset_libc);
+    ASSERT_EQ(0, sigprocmask64(SIG_SETMASK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, pthread_sigmask_setmask_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset_t sigset_libc;
-        sigfillset(&sigset_libc);
-        ASSERT_EQ(0, pthread_sigmask(SIG_SETMASK, &sigset_libc, nullptr));
-      },
-      sigset_type);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset_t sigset_libc;
+    sigfillset(&sigset_libc);
+    ASSERT_EQ(0, pthread_sigmask(SIG_SETMASK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, pthread_sigmask64_setmask_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset64_t sigset_libc;
-        sigfillset64(&sigset_libc);
-        ASSERT_EQ(0, pthread_sigmask64(SIG_SETMASK, &sigset_libc, nullptr));
-      },
-      SignalMaskFunctionType::RtAware);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset64_t sigset_libc;
+    sigfillset64(&sigset_libc);
+    ASSERT_EQ(0, pthread_sigmask64(SIG_SETMASK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, sigprocmask_block_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset_t sigset_libc;
-        sigfillset(&sigset_libc);
-        ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &sigset_libc, nullptr));
-      },
-      sigset_type);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset_t sigset_libc;
+    sigfillset(&sigset_libc);
+    ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, sigprocmask64_block_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset64_t sigset_libc;
-        sigfillset64(&sigset_libc);
-        ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &sigset_libc, nullptr));
-      },
-      SignalMaskFunctionType::RtAware);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset64_t sigset_libc;
+    sigfillset64(&sigset_libc);
+    ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, pthread_sigmask_block_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset_t sigset_libc;
-        sigfillset(&sigset_libc);
-        ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, &sigset_libc, nullptr));
-      },
-      sigset_type);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset_t sigset_libc;
+    sigfillset(&sigset_libc);
+    ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, &sigset_libc, nullptr));
+  });
 }
 
 TEST(signal, pthread_sigmask64_block_filter) {
-  TestSignalMaskFunction(
-      []() {
-        sigset64_t sigset_libc;
-        sigfillset64(&sigset_libc);
-        ASSERT_EQ(0, pthread_sigmask64(SIG_BLOCK, &sigset_libc, nullptr));
-      },
-      SignalMaskFunctionType::RtAware);
+  TestSignalMaskFunction([]() {
+    ClearSignalMask();
+    sigset64_t sigset_libc;
+    sigfillset64(&sigset_libc);
+    ASSERT_EQ(0, pthread_sigmask64(SIG_BLOCK, &sigset_libc, nullptr));
+  });
+}
+
+TEST(signal, sigprocmask_unblock_filter) {
+  TestSignalMaskFunction([]() {
+    FillSignalMask();
+    sigset_t sigset_libc;
+    sigfillset(&sigset_libc);
+    ASSERT_EQ(0, sigprocmask(SIG_UNBLOCK, &sigset_libc, nullptr));
+  });
+}
+
+TEST(signal, sigprocmask64_unblock_filter) {
+  TestSignalMaskFunction([]() {
+    FillSignalMask();
+    sigset64_t sigset_libc;
+    sigfillset64(&sigset_libc);
+    ASSERT_EQ(0, sigprocmask64(SIG_UNBLOCK, &sigset_libc, nullptr));
+  });
+}
+
+TEST(signal, pthread_sigmask_unblock_filter) {
+  TestSignalMaskFunction([]() {
+    FillSignalMask();
+    sigset_t sigset_libc;
+    sigfillset(&sigset_libc);
+    ASSERT_EQ(0, pthread_sigmask(SIG_UNBLOCK, &sigset_libc, nullptr));
+  });
+}
+
+TEST(signal, pthread_sigmask64_unblock_filter) {
+  TestSignalMaskFunction([]() {
+    FillSignalMask();
+    sigset64_t sigset_libc;
+    sigfillset64(&sigset_libc);
+    ASSERT_EQ(0, pthread_sigmask64(SIG_UNBLOCK, &sigset_libc, nullptr));
+  });
 }
 
 // glibc filters out signals via sigfillset, not the actual underlying functions.
 TEST(signal, sigset_filter) {
 #if defined(__BIONIC__)
-  TestSignalMaskFunction(
-      []() {
-        for (int i = 1; i <= 64; ++i) {
-          sigset(i, SIG_HOLD);
-        }
-      },
-      SignalMaskFunctionType::RtAware);
+  TestSignalMaskFunction([]() {
+    for (int i = 1; i <= 64; ++i) {
+      sigset(i, SIG_HOLD);
+    }
+  });
 #endif
 }
 
 TEST(signal, sighold_filter) {
 #if defined(__BIONIC__)
-  TestSignalMaskFunction(
-      []() {
-        for (int i = 1; i <= 64; ++i) {
-          sighold(i);
-        }
-      },
-      SignalMaskFunctionType::RtAware);
+  TestSignalMaskFunction([]() {
+    for (int i = 1; i <= 64; ++i) {
+      sighold(i);
+    }
+  });
 #endif
 }
 
@@ -525,23 +548,17 @@
 
 TEST(signal, sigblock_filter) {
 #if defined(__BIONIC__)
-  TestSignalMaskFunction(
-      []() {
-        int mask = ~0U;
-        ASSERT_EQ(0, sigblock(mask));
-      },
-      SignalMaskFunctionType::RtNonaware);
+  TestSignalMaskFunction([]() {
+    sigblock(~0U);
+  });
 #endif
 }
 
 TEST(signal, sigsetmask_filter) {
 #if defined(__BIONIC__)
-  TestSignalMaskFunction(
-      []() {
-        int mask = ~0U;
-        ASSERT_EQ(0, sigsetmask(mask));
-      },
-      SignalMaskFunctionType::RtNonaware);
+  TestSignalMaskFunction([]() {
+    sigsetmask(~0U);
+  });
 #endif
 }
 
diff --git a/tests/spawn_test.cpp b/tests/spawn_test.cpp
index a5e7e56..04b66d3 100644
--- a/tests/spawn_test.cpp
+++ b/tests/spawn_test.cpp
@@ -396,7 +396,13 @@
   // Check that's what happens...
   ProcStatus ps = {};
   GetChildStatus(&sa, &ps);
-  EXPECT_EQ(static_cast<uint64_t>(1 << (SIGALRM - 1)), ps.sigblk);
+
+  // TIMER_SIGNAL should also be blocked.
+  uint64_t expected_blocked = 0;
+  SignalSetAdd(&expected_blocked, SIGALRM);
+  SignalSetAdd(&expected_blocked, __SIGRTMIN + 0);
+  EXPECT_EQ(expected_blocked, ps.sigblk);
+
   EXPECT_EQ(static_cast<uint64_t>(0), ps.sigign);
 
   ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
@@ -421,8 +427,15 @@
   // Check that's what happens...
   ProcStatus ps = {};
   GetChildStatus(&sa, &ps);
-  EXPECT_EQ(static_cast<uint64_t>(0), ps.sigblk);
-  EXPECT_EQ(static_cast<uint64_t>(1 << (SIGCONT - 1)), ps.sigign);
+
+  // TIMER_SIGNAL should be blocked.
+  uint64_t expected_blocked = 0;
+  SignalSetAdd(&expected_blocked, __SIGRTMIN + 0);
+  EXPECT_EQ(expected_blocked, ps.sigblk);
+
+  uint64_t expected_ignored = 0;
+  SignalSetAdd(&expected_ignored, SIGCONT);
+  EXPECT_EQ(expected_ignored, ps.sigign);
 
   ASSERT_EQ(0, posix_spawnattr_destroy(&sa));
 }
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index 1f7f555..da083de 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -886,6 +886,8 @@
   VerifySysconf(_SC_XOPEN_VERSION, "_SC_XOPEN_VERSION", [](long v){return v == _XOPEN_VERSION && errno == 0;});
   VERIFY_SYSCONF_POSITIVE(_SC_ATEXIT_MAX);
   VERIFY_SYSCONF_POSITIVE(_SC_IOV_MAX);
+  VERIFY_SYSCONF_POSITIVE(_SC_UIO_MAXIOV);
+  EXPECT_EQ(sysconf(_SC_IOV_MAX), sysconf(_SC_UIO_MAXIOV));
   VERIFY_SYSCONF_POSITIVE(_SC_PAGESIZE);
   VERIFY_SYSCONF_POSITIVE(_SC_PAGE_SIZE);
   VerifySysconf(_SC_PAGE_SIZE, "_SC_PAGE_SIZE",