Merge "Add struct sigaction64 and sigaction64."

This commit is contained in:
Elliott Hughes 2018-02-02 17:11:20 +00:00 committed by Gerrit Code Review
commit ed95f37bc8
19 changed files with 173 additions and 126 deletions

View file

@ -59,6 +59,9 @@ to double check:
In the 64-bit ABI, `off_t` is always 64-bit.
For source compatibility, the names containing `64` are also available
in the 64-bit ABI even though they're identical to the non-`64` names.
## `sigset_t` is too small for real-time signals
@ -68,8 +71,15 @@ code. Android P (API level 28) adds `sigset64_t` and a corresponding function
for every function that takes a `sigset_t` (so `sigprocmask64` takes a
`sigset64_t` where `sigprocmask` takes a `sigset_t`).
On 32-bit Android, `struct sigaction` is also too small because it contains
a `sigset_t`. We also offer a `struct sigaction64` and `sigaction64` function
to work around this.
In the 64-bit ABI, `sigset_t` is the correct size for every architecture.
For source compatibility, the names containing `64` are also available
in the 64-bit ABI even though they're identical to the non-`64` names.
## `time_t` is 32-bit

View file

@ -49,11 +49,12 @@ New libc functions in P:
* `iconv`/`iconv_close`/`iconv_open` (adding <iconv.h>)
* `pthread_attr_getinheritsched`/`pthread_attr_setinheritsched`/`pthread_setschedprio`
* `pthread_mutexattr_getprotocol`/`pthread_mutexattr_setprotocol` (mutex priority inheritance)
* <signal.h> support for `sigaction64_t` and `sigset64_t` allowing LP32 access to real-time signals
* <spawn.h>
* `swab`
* `syncfs`
* `%C` and `%S` support in the printf family (previously only the wprintf family supported these).
* `%mc`/`%ms`/`%m[` support in the scanf family.
* `%C` and `%S` support in the printf family (previously only the wprintf family supported these)
* `%mc`/`%ms`/`%m[` support in the scanf family
New libc functions in O:
* `sendto` FORTIFY support

View file

@ -67,13 +67,10 @@ void abort() {
sigprocmask64(SIG_SETMASK, &mask, nullptr);
inline_tgkill(pid, tid, SIGABRT);
// If SIGABRT ignored, or caught and the handler returns,
// If SIGABRT is ignored or it's caught and the handler returns,
// remove the SIGABRT signal handler and raise SIGABRT again.
struct sigaction sa;
sa.sa_handler = SIG_DFL;
sa.sa_flags = SA_RESTART;
sigemptyset(&sa.sa_mask);
sigaction(SIGABRT, &sa, &sa);
struct sigaction64 sa = { .sa_handler = SIG_DFL, .sa_flags = SA_RESTART };
sigaction64(SIGABRT, &sa, nullptr);
sigprocmask64(SIG_SETMASK, &mask, nullptr);
inline_tgkill(pid, tid, SIGABRT);

View file

@ -27,6 +27,7 @@
*/
#include <signal.h>
#include <string.h>
extern "C" void __restore_rt(void);
extern "C" void __restore(void);
@ -75,28 +76,49 @@ int sigaction(int signal, const struct sigaction* bionic_new_action, struct siga
return result;
}
__strong_alias(sigaction64, sigaction);
#else
extern "C" int __rt_sigaction(int, const struct sigaction64*, struct sigaction64*, size_t);
extern "C" int __sigaction(int, const struct sigaction*, struct sigaction*);
int sigaction(int signal, const struct sigaction* bionic_new_action, struct sigaction* bionic_old_action) {
int sigaction(int signal, const struct sigaction* bionic_new, struct sigaction* bionic_old) {
// The 32-bit ABI is broken. struct sigaction includes a too-small sigset_t,
// so we have to use sigaction(2) rather than rt_sigaction(2).
struct sigaction kernel_new_action;
if (bionic_new_action != NULL) {
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 = bionic_new_action->sa_mask;
#if defined(SA_RESTORER)
kernel_new_action.sa_restorer = bionic_new_action->sa_restorer;
if (!(kernel_new_action.sa_flags & SA_RESTORER)) {
kernel_new_action.sa_flags |= SA_RESTORER;
kernel_new_action.sa_restorer = (kernel_new_action.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
}
#endif
// so we have to translate to struct sigaction64 first.
struct sigaction64 kernel_new;
if (bionic_new) {
kernel_new = {};
kernel_new.sa_flags = bionic_new->sa_flags;
kernel_new.sa_handler = bionic_new->sa_handler;
memcpy(&kernel_new.sa_mask, &bionic_new->sa_mask, sizeof(bionic_new->sa_mask));
}
return __sigaction(signal, (bionic_new_action != NULL) ? &kernel_new_action : NULL, bionic_old_action);
struct sigaction64 kernel_old;
int result = sigaction64(signal, bionic_new ? &kernel_new : nullptr, &kernel_old);
if (bionic_old) {
*bionic_old = {};
bionic_old->sa_flags = kernel_old.sa_flags;
bionic_old->sa_handler = kernel_old.sa_handler;
memcpy(&bionic_old->sa_mask, &kernel_old.sa_mask, sizeof(bionic_old->sa_mask));
}
return result;
}
int sigaction64(int signal, const struct sigaction64* bionic_new, struct sigaction64* bionic_old) {
struct sigaction64 kernel_new;
if (bionic_new) {
kernel_new = *bionic_new;
if (!(kernel_new.sa_flags & SA_RESTORER)) {
kernel_new.sa_flags |= SA_RESTORER;
kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
}
}
return __rt_sigaction(signal,
bionic_new ? &kernel_new : nullptr,
bionic_old,
sizeof(kernel_new.sa_mask));
}
#endif

View file

@ -147,22 +147,19 @@ int sighold(int sig) {
}
int sigignore(int sig) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
if (sigemptyset(&sa.sa_mask) == -1) return -1;
sa.sa_handler = SIG_IGN;
return sigaction(sig, &sa, nullptr);
struct sigaction64 sa = { .sa_handler = SIG_IGN };
return sigaction64(sig, &sa, nullptr);
}
int siginterrupt(int sig, int flag) {
struct sigaction act;
sigaction(sig, nullptr, &act);
struct sigaction64 act;
sigaction64(sig, nullptr, &act);
if (flag) {
act.sa_flags &= ~SA_RESTART;
} else {
act.sa_flags |= SA_RESTART;
}
return sigaction(sig, &act, nullptr);
return sigaction64(sig, &act, nullptr);
}
template <typename SigSetT>
@ -185,16 +182,8 @@ int sigismember64(const sigset64_t* set, int sig) {
}
__LIBC_HIDDEN__ sighandler_t _signal(int sig, sighandler_t handler, int flags) {
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_handler = handler;
sa.sa_flags = flags;
if (sigaction(sig, &sa, &sa) == -1) {
return SIG_ERR;
}
return sa.sa_handler;
struct sigaction64 sa = { .sa_handler = handler, .sa_flags = flags };
return (sigaction64(sig, &sa, &sa) == -1) ? SIG_ERR : sa.sa_handler;
}
sighandler_t signal(int sig, sighandler_t handler) {
@ -262,15 +251,11 @@ int sigrelse(int sig) {
}
sighandler_t sigset(int sig, sighandler_t disp) {
struct sigaction new_sa;
if (disp != SIG_HOLD) {
memset(&new_sa, 0, sizeof(new_sa));
new_sa.sa_handler = disp;
sigemptyset(&new_sa.sa_mask);
}
struct sigaction64 new_sa;
if (disp != SIG_HOLD) new_sa = { .sa_handler = disp };
struct sigaction old_sa;
if (sigaction(sig, (disp == SIG_HOLD) ? nullptr : &new_sa, &old_sa) == -1) {
struct sigaction64 old_sa;
if (sigaction64(sig, (disp == SIG_HOLD) ? nullptr : &new_sa, &old_sa) == -1) {
return SIG_ERR;
}

View file

@ -98,17 +98,17 @@ static void ApplyAttrs(short flags, const posix_spawnattr_t* attr) {
// POSIX: "Signals set to be caught by the calling process shall be
// set to the default action in the child process."
bool use_sigdefault = ((flags & POSIX_SPAWN_SETSIGDEF) != 0);
const struct sigaction default_sa = { .sa_handler = SIG_DFL };
const struct sigaction64 default_sa = { .sa_handler = SIG_DFL };
for (int s = 1; s < _NSIG; ++s) {
bool reset = false;
if (use_sigdefault && sigismember64(&(*attr)->sigdefault.sigset64, s)) {
reset = true;
} else {
struct sigaction current;
if (sigaction(s, nullptr, &current) == -1) _exit(127);
struct sigaction64 current;
if (sigaction64(s, nullptr, &current) == -1) _exit(127);
reset = (current.sa_handler != SIG_IGN && current.sa_handler != SIG_DFL);
}
if (reset && sigaction(s, &default_sa, nullptr) == -1) _exit(127);
if (reset && sigaction64(s, &default_sa, nullptr) == -1) _exit(127);
}
if ((flags & POSIX_SPAWN_SETPGROUP) != 0 && setpgid(0, (*attr)->pgroup) == -1) _exit(127);

View file

@ -40,7 +40,8 @@
/* For 64-bit (and mips), the kernel's struct sigaction doesn't match the
* POSIX one, so we need to expose our own and translate behind the scenes.
* For 32-bit, we're stuck with the definitions we already shipped,
* even though they contain a sigset_t that's too small. */
* even though they contain a sigset_t that's too small. See sigaction64.
*/
#define sigaction __kernel_sigaction
#include <linux/signal.h>
#undef sigaction
@ -89,43 +90,65 @@ typedef struct { unsigned long __bits[_KERNEL__NSIG/LONG_BIT]; } sigset64_t;
#if defined(__LP64__)
#define __SIGACTION_BODY \
int sa_flags; \
union { \
sighandler_t sa_handler; \
void (*sa_sigaction)(int, struct siginfo*, void*); \
}; \
sigset_t sa_mask; \
void (*sa_restorer)(void); \
struct sigaction { __SIGACTION_BODY };
struct sigaction64 { __SIGACTION_BODY };
#undef __SIGACTION_BODY
#elif defined(__mips__)
#define __SIGACTION_BODY \
int sa_flags; \
union { \
sighandler_t sa_handler; \
void (*sa_sigaction)(int, struct siginfo*, void*); \
}; \
sigset_t sa_mask; \
struct sigaction { __SIGACTION_BODY };
struct sigaction64 { __SIGACTION_BODY };
#undef __SIGACTION_BODY
#else
#undef sa_handler
#undef sa_sigaction
struct sigaction {
int sa_flags;
union {
sighandler_t sa_handler;
void (*sa_sigaction)(int, struct siginfo*, void*);
};
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
#elif defined(__mips__)
struct sigaction {
int sa_flags;
/* This matches the kernel's internal structure. */
struct sigaction64 {
union {
sighandler_t sa_handler;
void (*sa_sigaction) (int, struct siginfo*, void*);
void (*sa_sigaction)(int, struct siginfo*, void*);
};
sigset_t sa_mask;
};
#else
struct sigaction {
union {
sighandler_t _sa_handler;
void (*_sa_sigaction)(int, struct siginfo*, void*);
} _u;
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
sigset64_t sa_mask;
};
#endif
// TODO: sigaction contains a sigset_t that's too small on LP32.
int sigaction(int __signal, const struct sigaction* __new_action, struct sigaction* __old_action);
int sigaction64(int __signal, const struct sigaction64* __new_action, struct sigaction64* __old_action) __INTRODUCED_IN(28);
int siginterrupt(int __signal, int __flag);
@ -191,4 +214,4 @@ __END_DECLS
#include <android/legacy_signal_inlines.h>
#endif /* _SIGNAL_H_ */
#endif

View file

@ -1386,6 +1386,7 @@ LIBC_P { # introduced=P
sethostent;
setnetent;
setprotoent;
sigaction64;
sigaddset64;
sigdelset64;
sigemptyset64;

View file

@ -1306,6 +1306,7 @@ LIBC_P { # introduced=P
sethostent;
setnetent;
setprotoent;
sigaction64;
sigaddset64;
sigdelset64;
sigemptyset64;

View file

@ -1411,6 +1411,7 @@ LIBC_P { # introduced=P
sethostent;
setnetent;
setprotoent;
sigaction64;
sigaddset64;
sigdelset64;
sigemptyset64;

View file

@ -1370,6 +1370,7 @@ LIBC_P { # introduced=P
sethostent;
setnetent;
setprotoent;
sigaction64;
sigaddset64;
sigdelset64;
sigemptyset64;

View file

@ -1306,6 +1306,7 @@ LIBC_P { # introduced=P
sethostent;
setnetent;
setprotoent;
sigaction64;
sigaddset64;
sigdelset64;
sigemptyset64;

View file

@ -1368,6 +1368,7 @@ LIBC_P { # introduced=P
sethostent;
setnetent;
setprotoent;
sigaction64;
sigaddset64;
sigdelset64;
sigemptyset64;

View file

@ -1306,6 +1306,7 @@ LIBC_P { # introduced=P
sethostent;
setnetent;
setprotoent;
sigaction64;
sigaddset64;
sigdelset64;
sigemptyset64;

View file

@ -59,13 +59,10 @@ BacktraceData::BacktraceData(DebugData* debug_data, const Config& config, size_t
bool BacktraceData::Initialize(const Config& config) {
enabled_ = config.backtrace_enabled();
if (config.backtrace_enable_on_signal()) {
struct sigaction enable_act;
memset(&enable_act, 0, sizeof(enable_act));
struct sigaction64 enable_act = {};
enable_act.sa_sigaction = ToggleBacktraceEnable;
enable_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
sigemptyset(&enable_act.sa_mask);
if (sigaction(config.backtrace_signal(), &enable_act, nullptr) != 0) {
if (sigaction64(config.backtrace_signal(), &enable_act, nullptr) != 0) {
error_log("Unable to set up backtrace signal enable function: %s", strerror(errno));
return false;
}
@ -73,13 +70,10 @@ bool BacktraceData::Initialize(const Config& config) {
config.backtrace_signal(), getpid());
}
struct sigaction act;
memset(&act, 0, sizeof(act));
struct sigaction64 act = {};
act.sa_sigaction = EnableDump;
act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
sigemptyset(&act.sa_mask);
if (sigaction(config.backtrace_dump_signal(), &act, nullptr) != 0) {
if (sigaction64(config.backtrace_dump_signal(), &act, nullptr) != 0) {
error_log("Unable to set up backtrace dump signal function: %s", strerror(errno));
return false;
}

View file

@ -179,13 +179,10 @@ RecordData::RecordData() {
}
bool RecordData::Initialize(const Config& config) {
struct sigaction dump_act;
memset(&dump_act, 0, sizeof(dump_act));
struct sigaction64 dump_act = {};
dump_act.sa_sigaction = RecordDump;
dump_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
sigemptyset(&dump_act.sa_mask);
if (sigaction(config.record_allocs_signal(), &dump_act, nullptr) != 0) {
if (sigaction64(config.record_allocs_signal(), &dump_act, nullptr) != 0) {
error_log("Unable to set up record dump signal function: %s", strerror(errno));
return false;
}

View file

@ -21,25 +21,28 @@
#include <gtest/gtest.h>
#if !defined(__BIONIC__)
#define sigaction64 sigaction
#endif
class BionicDeathTest : public testing::Test {
protected:
virtual void SetUp() {
// Suppress debuggerd stack traces. Too slow.
for (int signo : { SIGABRT, SIGBUS, SIGSEGV, SIGSYS }) {
struct sigaction action = {};
action.sa_handler = SIG_DFL;
sigaction(signo, &action, &previous_);
struct sigaction64 action = { .sa_handler = SIG_DFL };
sigaction64(signo, &action, &previous_);
}
}
virtual void TearDown() {
for (int signo : { SIGABRT, SIGBUS, SIGSEGV, SIGSYS }) {
sigaction(signo, &previous_, nullptr);
sigaction64(signo, &previous_, nullptr);
}
}
private:
struct sigaction previous_;
struct sigaction64 previous_;
};
#endif // BIONIC_TESTS_BIONIC_DEATH_TEST_H_

View file

@ -26,6 +26,7 @@
#define posix_spawnattr_setsigdefault64 posix_spawnattr_setsigdefault
#define posix_spawnattr_setsigmask64 posix_spawnattr_setsigmask
#define pthread_sigmask64 pthread_sigmask
#define sigaction64 sigaction
#define sigaddset64 sigaddset
#define sigdelset64 sigdelset
#define sigemptyset64 sigemptyset
@ -47,7 +48,7 @@ class ScopedSignalHandler {
memset(&action_, 0, sizeof(action_));
action_.sa_flags = sa_flags;
action_.sa_handler = handler;
sigaction(signal_number_, &action_, &old_action_);
sigaction64(signal_number_, &action_, &old_action_);
}
ScopedSignalHandler(int signal_number, void (*action)(int, siginfo_t*, void*),
@ -56,20 +57,20 @@ class ScopedSignalHandler {
memset(&action_, 0, sizeof(action_));
action_.sa_flags = sa_flags;
action_.sa_sigaction = action;
sigaction(signal_number_, &action_, &old_action_);
sigaction64(signal_number_, &action_, &old_action_);
}
ScopedSignalHandler(int signal_number) : signal_number_(signal_number) {
sigaction(signal_number, nullptr, &old_action_);
sigaction64(signal_number, nullptr, &old_action_);
}
~ScopedSignalHandler() {
sigaction(signal_number_, &old_action_, NULL);
sigaction64(signal_number_, &old_action_, NULL);
}
private:
struct sigaction action_;
struct sigaction old_action_;
struct sigaction64 action_;
struct sigaction64 old_action_;
const int signal_number_;
};

View file

@ -269,55 +269,63 @@ TEST(signal, sigsuspend64_sigpending64) {
ASSERT_EQ(1, g_sigsuspend64_signal_handler_call_count);
}
static void EmptySignalHandler(int) {}
static void EmptySignalAction(int, siginfo_t*, void*) {}
TEST(signal, sigaction) {
template <typename SigActionT, typename SigSetT>
static void TestSigAction(int (sigaction_fn)(int, const SigActionT*, SigActionT*),
int (sigaddset_fn)(SigSetT*, int),
int sig) {
// Both bionic and glibc set SA_RESTORER when talking to the kernel on arm,
// arm64, x86, and x86-64. The version of glibc we're using also doesn't
// define SA_RESTORER, but luckily it's the same value everywhere, and mips
// doesn't use the bit for anything.
static const unsigned sa_restorer = 0x4000000;
// See what's currently set for SIGALRM.
struct sigaction original_sa;
memset(&original_sa, 0, sizeof(original_sa));
ASSERT_EQ(0, sigaction(SIGALRM, NULL, &original_sa));
// See what's currently set for this signal.
SigActionT original_sa = {};
ASSERT_EQ(0, sigaction_fn(sig, NULL, &original_sa));
ASSERT_TRUE(original_sa.sa_handler == NULL);
ASSERT_TRUE(original_sa.sa_sigaction == NULL);
ASSERT_EQ(0U, original_sa.sa_flags & ~sa_restorer);
// Set a traditional sa_handler signal handler.
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigaddset(&sa.sa_mask, SIGALRM);
auto no_op_signal_handler = [](int) {};
SigActionT sa = {};
sigaddset_fn(&sa.sa_mask, sig);
sa.sa_flags = SA_ONSTACK;
sa.sa_handler = EmptySignalHandler;
ASSERT_EQ(0, sigaction(SIGALRM, &sa, NULL));
sa.sa_handler = no_op_signal_handler;
ASSERT_EQ(0, sigaction_fn(sig, &sa, NULL));
// Check that we can read it back.
memset(&sa, 0, sizeof(sa));
ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa));
ASSERT_TRUE(sa.sa_handler == EmptySignalHandler);
sa = {};
ASSERT_EQ(0, sigaction_fn(sig, NULL, &sa));
ASSERT_TRUE(sa.sa_handler == no_op_signal_handler);
ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler);
ASSERT_EQ(static_cast<unsigned>(SA_ONSTACK), sa.sa_flags & ~sa_restorer);
// Set a new-style sa_sigaction signal handler.
memset(&sa, 0, sizeof(sa));
sigaddset(&sa.sa_mask, SIGALRM);
auto no_op_sigaction = [](int, siginfo_t*, void*) {};
sa = {};
sigaddset_fn(&sa.sa_mask, sig);
sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
sa.sa_sigaction = EmptySignalAction;
ASSERT_EQ(0, sigaction(SIGALRM, &sa, NULL));
sa.sa_sigaction = no_op_sigaction;
ASSERT_EQ(0, sigaction_fn(sig, &sa, NULL));
// Check that we can read it back.
memset(&sa, 0, sizeof(sa));
ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa));
ASSERT_TRUE(sa.sa_sigaction == EmptySignalAction);
sa = {};
ASSERT_EQ(0, sigaction_fn(sig, NULL, &sa));
ASSERT_TRUE(sa.sa_sigaction == no_op_sigaction);
ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler);
ASSERT_EQ(static_cast<unsigned>(SA_ONSTACK | SA_SIGINFO), sa.sa_flags & ~sa_restorer);
// Put everything back how it was.
ASSERT_EQ(0, sigaction(SIGALRM, &original_sa, NULL));
ASSERT_EQ(0, sigaction_fn(sig, &original_sa, NULL));
}
TEST(signal, sigaction) {
TestSigAction(sigaction, sigaddset, SIGALRM);
}
TEST(signal, sigaction64_SIGRTMIN) {
TestSigAction(sigaction64, sigaddset64, SIGRTMIN);
}
TEST(signal, sys_signame) {
@ -495,8 +503,7 @@ TEST(signal, rt_tgsigqueueinfo) {
"* https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=66dd34ad31e5963d72a700ec3f2449291d322921\n";
static siginfo received;
struct sigaction handler;
memset(&handler, 0, sizeof(handler));
struct sigaction handler = {};
handler.sa_sigaction = [](int, siginfo_t* siginfo, void*) { received = *siginfo; };
handler.sa_flags = SA_SIGINFO;