diff --git a/libc/include/signal.h b/libc/include/signal.h index 6432c189b..9d3badccf 100644 --- a/libc/include/signal.h +++ b/libc/include/signal.h @@ -28,6 +28,7 @@ #ifndef _SIGNAL_H_ #define _SIGNAL_H_ +#include #include #include /* For LONG_BIT */ #include /* For memset() */ @@ -53,45 +54,57 @@ typedef int sig_atomic_t; # define _NSIG 64 #endif -extern const char * const sys_siglist[]; -extern const char * const sys_signame[]; +extern const char* const sys_siglist[]; +extern const char* const sys_signame[]; -static __inline__ int sigismember(sigset_t *set, int signum) -{ - unsigned long *local_set = (unsigned long *)set; - signum--; - return (int)((local_set[signum/LONG_BIT] >> (signum%LONG_BIT)) & 1); +static __inline__ int sigismember(sigset_t* set, int signum) { + if (set == NULL || signum < 1 || signum >= 8*sizeof(sigset_t)) { + errno = EINVAL; + return -1; + } + unsigned long* local_set = (unsigned long*) set; + signum--; + return (int) ((local_set[signum/LONG_BIT] >> (signum%LONG_BIT)) & 1); } - -static __inline__ int sigaddset(sigset_t *set, int signum) -{ - unsigned long *local_set = (unsigned long *)set; - signum--; - local_set[signum/LONG_BIT] |= 1UL << (signum%LONG_BIT); - return 0; +static __inline__ int sigaddset(sigset_t* set, int signum) { + if (set == NULL || signum < 1 || signum >= 8*sizeof(sigset_t)) { + errno = EINVAL; + return -1; + } + unsigned long* local_set = (unsigned long*) set; + signum--; + local_set[signum/LONG_BIT] |= 1UL << (signum%LONG_BIT); + return 0; } - -static __inline__ int sigdelset(sigset_t *set, int signum) -{ - unsigned long *local_set = (unsigned long *)set; - signum--; - local_set[signum/LONG_BIT] &= ~(1UL << (signum%LONG_BIT)); - return 0; +static __inline__ int sigdelset(sigset_t* set, int signum) { + if (set == NULL || signum < 1 || signum >= 8*sizeof(sigset_t)) { + errno = EINVAL; + return -1; + } + unsigned long* local_set = (unsigned long*) set; + signum--; + local_set[signum/LONG_BIT] &= ~(1UL << (signum%LONG_BIT)); + return 0; } - -static __inline__ int sigemptyset(sigset_t *set) -{ - memset(set, 0, sizeof *set); - return 0; +static __inline__ int sigemptyset(sigset_t* set) { + if (set == NULL) { + errno = EINVAL; + return -1; + } + memset(set, 0, sizeof *set); + return 0; } -static __inline__ int sigfillset(sigset_t *set) -{ - memset(set, ~0, sizeof *set); - return 0; +static __inline__ int sigfillset(sigset_t* set) { + if (set == NULL) { + errno = EINVAL; + return -1; + } + memset(set, ~0, sizeof *set); + return 0; } diff --git a/tests/Android.mk b/tests/Android.mk index 0da395103..abc6f52d1 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -59,6 +59,7 @@ test_src_files = \ libgen_test.cpp \ pthread_test.cpp \ regex_test.cpp \ + signal_test.cpp \ stack_protector_test.cpp \ stdio_test.cpp \ stdlib_test.cpp \ diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp new file mode 100644 index 000000000..a54f14d31 --- /dev/null +++ b/tests/signal_test.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2012 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 + +#include +#include + +template +static void TestSigSet1(Fn fn) { + // NULL sigset_t*. + sigset_t* set_ptr = NULL; + errno = 0; + ASSERT_EQ(-1, fn(set_ptr)); + ASSERT_EQ(EINVAL, errno); + + // Non-NULL. + sigset_t set; + errno = 0; + ASSERT_EQ(0, fn(&set)); + ASSERT_EQ(0, errno); +} + +template +static void TestSigSet2(Fn fn) { + // NULL sigset_t*. + sigset_t* set_ptr = NULL; + errno = 0; + ASSERT_EQ(-1, fn(set_ptr, SIGSEGV)); + ASSERT_EQ(EINVAL, errno); + + sigset_t set; + sigemptyset(&set); + + int min_signal = SIGHUP; + int max_signal = SIGRTMAX; + +#if __BIONIC__ + // bionic's sigset_t is too small: 32 bits instead of 64. + // This means you can't refer to any of the real-time signals. + // See http://b/3038348 and http://b/5828899. + max_signal = 31; +#else + // Other C libraries are perfectly capable of using their largest signal. + ASSERT_GE(sizeof(sigset_t) * 8, static_cast(SIGRTMAX)); +#endif + + // Bad signal number: too small. + errno = 0; + ASSERT_EQ(-1, fn(&set, 0)); + ASSERT_EQ(EINVAL, errno); + + // Bad signal number: too high. + errno = 0; + ASSERT_EQ(-1, fn(&set, max_signal + 1)); + ASSERT_EQ(EINVAL, errno); + + // Good signal numbers, low and high ends of range. + errno = 0; + ASSERT_EQ(0, fn(&set, min_signal)); + ASSERT_EQ(0, errno); + ASSERT_EQ(0, fn(&set, max_signal)); + ASSERT_EQ(0, errno); +} + +TEST(signal, sigismember_invalid) { + TestSigSet2(sigismember); +} + +TEST(signal, sigaddset_invalid) { + TestSigSet2(sigaddset); +} + +TEST(signal, sigdelset_invalid) { + TestSigSet2(sigdelset); +} + +TEST(signal, sigemptyset_invalid) { + TestSigSet1(sigemptyset); +} + +TEST(signal, sigfillset_invalid) { + TestSigSet1(sigfillset); +}