1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <unistd.h>
17 #include <string.h>
18 #include <sys/types.h>
19 #include <sys/shm.h>
20 #include <fcntl.h>
21 #include "log.h"
22 #include "utils.h"
23 #include "SignalTest.h"
24
25 using namespace testing::ext;
26
27 // static member must init before use.
28 int IpcSignalTest::mReceivedSignal = 0;
29 int IpcSignalTest::mShmid = 0;
30 siginfo_t IpcSignalTest::mSiginfo;
31
32
33 // special signal handler for function 'abort'
SigAbortHandler(int signum)34 void IpcSignalTest::SigAbortHandler(int signum)
35 {
36 LOG("handler: recv a signal: %d", signum);
37 int *shared = static_cast<int*>(shmat(mShmid, nullptr, 0));
38 if (shared == reinterpret_cast<int*>(-1)) {
39 LOG("SigAbortHandler: shmat fail, errno = %d", errno);
40 } else {
41 LOG("shared: %p", shared);
42 *shared = signum;
43 if (shmdt(shared) == -1) {
44 LOG("SigAbortHandler: shmdt errno = %d", errno);
45 }
46 }
47 }
48
49 // special signal handler for function 'sigaction'
SigactionHandler(int signum,siginfo_t * si,void * ucontext)50 void IpcSignalTest::SigactionHandler(int signum, siginfo_t* si, void* ucontext)
51 {
52 LOG("handler recv a signal: %s(%d)", ALL_SIGNALS[signum].signame, signum);
53 mReceivedSignal = signum;
54 // siginfo_t para is not supported yet
55 }
56
57 // general signal handler. note: not thread-safe
SignalHandler(int signum)58 void IpcSignalTest::SignalHandler(int signum)
59 {
60 LOG("handler recv a signal: %s(%d)", ALL_SIGNALS[signum].signame, signum);
61 mReceivedSignal = signum;
62 }
63
64 SignalNameAction const ALL_SIGNALS[MAX_SIGNAL] = {
65 {"NA", "Unknown signal", TERMINATE},
66 {"SIGHUP", "Hangup", TERMINATE}, // 1
67 {"SIGINT", "Interrupt", TERMINATE},
68 {"SIGQUIT", "Quit", COREDUMP},
69 {"SIGILL", "Illegal instruction", COREDUMP},
70 {"SIGTRAP", "Trace/breakpoint trap", COREDUMP},
71 {"SIGABRT", "Aborted", COREDUMP}, // alias: SIGIOT
72 {"SIGBUS", "Bus error", COREDUMP},
73 {"SIGFPE", "Arithmetic exception", COREDUMP},
74 {"SIGKILL", "Killed", TERMINATE},
75 {"SIGUSR1", "User defined signal 1", TERMINATE}, // 10
76 {"SIGSEGV", "Segmentation fault", COREDUMP},
77 {"SIGUSR2", "User defined signal 2", TERMINATE},
78 {"SIGPIPE", "Broken pipe", TERMINATE},
79 {"SIGALRM", "Alarm clock", TERMINATE},
80 {"SIGTERM", "Terminated", TERMINATE},
81 {"SIGSTKFLT", "Stack fault", TERMINATE},
82 {"SIGCHLD", "Child process status", IGNORE}, // alias: SIGCLD
83 {"SIGCONT", "Continued", CONTINUE},
84 {"SIGSTOP", "Stopped (signal)", STOP},
85 {"SIGTSTP", "Stopped", STOP}, // 20
86 {"SIGTTIN", "Stopped (tty input)", STOP},
87 {"SIGTTOU", "Stopped (tty output)", STOP},
88 {"SIGURG", "Urgent I/O condition", IGNORE},
89 {"SIGXCPU", "CPU time limit exceeded", COREDUMP},
90 {"SIGXFSZ", "File size limit exceeded", COREDUMP},
91 {"SIGVTALRM", "Virtual timer expired", TERMINATE},
92 {"SIGPROF", "Profiling timer expired", TERMINATE},
93 {"SIGWINCH", "Window changed", IGNORE},
94 {"SIGIO", "I/O possible", TERMINATE}, // alias: SIGPOLL
95 {"SIGPWR", "Power failure", TERMINATE}, // alias: SIGINFO, 30
96 };
97
DefaultActionTest(const int signum,const bool expectStop,const bool coredump)98 void IpcSignalTest::DefaultActionTest(const int signum, const bool expectStop, const bool coredump)
99 {
100 pid_t pid = fork();
101 ASSERT_TRUE(pid >= 0) << "======== Fork Error! =========";
102 if (pid > 0) { // parent
103 Msleep(20);
104 LOGD("before kill");
105 kill(pid, signum);
106 if (!expectStop) {
107 Msleep(20);
108 AssertProcAlive(pid);
109 Msleep(20);
110 WaitProcExitedOK(pid);
111 } else {
112 WaitProcKilled(pid, signum);
113 if (coredump) {
114 // check codedump, liteos not support yet
115 }
116 }
117 } else { // child
118 LOGD("child start");
119 KeepRun(KEEP_RUN_TIME);
120 if (expectStop) {
121 LOG("Child should has been Terminated, but still alive.");
122 exit(1);
123 }
124 exit(0);
125 }
126 }
127
SendAndRecvTest(const int signum)128 void IpcSignalTest::SendAndRecvTest(const int signum)
129 {
130 pid_t pid1, pid2;
131 bool useBrother = GetRandom(100) % 2; // if use brother to send the signal
132 pid1 = fork();
133 ASSERT_TRUE(pid1 >= 0) << "======== Fork1 Error! =========";
134 if (pid1 > 0) { // parent
135 LOGD("in parent...");
136 if (useBrother) {
137 pid2 = fork();
138 ASSERT_TRUE(pid2 >= 0) << "======== Fork2 Error! =========";
139 if (pid2 == 0) { // child 2
140 Msleep(50);
141 kill(pid1, signum);
142 exit(0);
143 }
144 // parent
145 Msleep(20);
146 LOG("check if child2 exited OK");
147 WaitProcExitedOK(pid2);
148 } else {
149 Msleep(100);
150 kill(pid1, signum);
151 }
152 AssertProcAlive(pid1);
153
154 Msleep(20); // child should exited now
155 LOG("check if child exited OK");
156 WaitProcExitedOK(pid1);
157 } else { // child 1, the receiver
158 LOGD("in child, pid=%d", getpid());
159 handler_type rt = signal(signum, SignalHandler);
160 if (rt == SIG_ERR) {
161 LOG("set %d signal handler failed, errno=%d", signum, errno);
162 exit(1);
163 }
164 Msleep(150);
165 if (mReceivedSignal != signum) {
166 LOG("SignalHandler check fail, expected=%d, received=%d", signum, mReceivedSignal);
167 exit(1);
168 }
169 LOGD("child sleeping....");
170 Msleep(20);
171 LOGD("child exit 0....");
172 exit(0);
173 }
174 }
175
CheckSigString(const char * outfile,const char * expectStr)176 int IpcSignalTest::CheckSigString(const char* outfile, const char* expectStr)
177 {
178 const int bufLen = 64;
179 char buffer[bufLen];
180
181 FILE *fp = fopen(outfile, "rb");
182 size_t bytes = fread(buffer, 1, bufLen, fp);
183 buffer[bytes] = 0;
184 LOGD("%d bytes read from logfile:%s", bytes, buffer);
185 fclose(fp);
186 size_t expectLen = strlen(expectStr);
187 LOGD("expect string len = %d", expectLen);
188 if (bytes != (expectLen + 1)) {
189 LOG("bytes number read from stderr file error, expect:%d, actual:%d",
190 expectLen + 1, bytes);
191 return 1;
192 }
193 return strncmp(expectStr, buffer, expectLen);
194 }
195
SignalFailTest(int signum,handler_type h,int expectErrno)196 void IpcSignalTest::SignalFailTest(int signum, handler_type h, int expectErrno)
197 {
198 errno = 0;
199 handler_type rt = signal(signum, h);
200 ASSERT_EQ(rt, SIG_ERR) << "signal error for " << signum;
201 ASSERT_EQ(errno, expectErrno) << "signal error for " << signum;
202 }
SigpendingFailTest(sigset_t * pset)203 void IpcSignalTest::SigpendingFailTest(sigset_t* pset)
204 {
205 errno = 0;
206 int rt = sigpending(pset);
207 ASSERT_EQ(rt, -1);
208 ASSERT_EQ(errno, EFAULT);
209 }
SigtimedwaitFailTest(const sigset_t * set,siginfo_t * info,const timespec * timeout,int expectErrno)210 void IpcSignalTest::SigtimedwaitFailTest(const sigset_t *set, siginfo_t* info, const timespec* timeout, int expectErrno)
211 {
212 errno = 0;
213 int rt = sigtimedwait(set, info, timeout);
214 ASSERT_EQ(rt, -1);
215 ASSERT_EQ(errno, expectErrno);
216 }
217
218 // thread function for testcase: 'testPthreadkill'
ThreadFunc1(void * arg)219 void* IpcSignalTest::ThreadFunc1(void* arg)
220 {
221 int sigNo = (int)((uintptr_t)arg);
222 signal(sigNo, SignalHandler);
223 Msleep(60);
224 return nullptr;
225 }
226
227 // thread function for testcase: 'testPthreadkillMain'
ThreadFunc2(void * arg)228 void* IpcSignalTest::ThreadFunc2(void* arg)
229 {
230 pthread_t* tid = (pthread_t*)arg;
231 int ret = pthread_kill(*tid, SIGINT);
232 if (ret != 0) {
233 LOG("pthread_kill failed, errno=%d", ret);
234 return (void*)1;
235 }
236 LOG("pthread_kill send signal(%d) ok", SIGINT);
237 return nullptr;
238 }
239
240 // thread function for testcase: 'testPthreadSigmask'
ThreadFuncForSigmask1(void * arg)241 void* IpcSignalTest::ThreadFuncForSigmask1(void* arg)
242 {
243 int rt;
244 int type = (int)((uintptr_t)arg);
245 if (type == 1) {
246 signal(SIGINT, SignalHandler);
247 }
248
249 LOG("block SIGINT");
250 sigset_t sigmask, oldmask;
251 sigemptyset(&sigmask);
252 sigemptyset(&oldmask);
253 sigaddset(&sigmask, SIGINT);
254 sigaddset(&sigmask, SIGUSR1);
255 rt = pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
256 EXPECT_EQ(rt, 0);
257 raise(SIGINT);
258 EXPECT_EQ(mReceivedSignal, 0) << "SignalHandler check fail, SIGINT should has blocked!";
259
260 LOG("unblock SIGINT");
261 sigemptyset(&sigmask);
262 sigaddset(&sigmask, SIGINT);
263 rt = pthread_sigmask(SIG_UNBLOCK, &sigmask, nullptr);
264 EXPECT_EQ(rt, 0);
265
266 LOG("check the new block set");
267 sigemptyset(&oldmask);
268 pthread_sigmask(SIG_UNBLOCK, nullptr, &oldmask);
269 EXPECT_EQ(sigismember(&oldmask, SIGINT), 0) << "SIGINT should has deleted from block set!";
270 EXPECT_EQ(sigismember(&oldmask, SIGUSR1), 1) << "SIGUSR1 should still in block set!";
271
272 EXPECT_EQ(mReceivedSignal, SIGINT) << "SignalHandler check fail, SIGINT should deliver after unblock!";
273 return nullptr;
274 }
275
276 // thread function for testcase: 'testPthreadSigmaskInherit'
ThreadFuncForSigmask2(void * arg)277 void* IpcSignalTest::ThreadFuncForSigmask2(void* arg)
278 {
279 sigset_t sigmask, oldmask;
280 sigemptyset(&sigmask);
281 sigemptyset(&oldmask);
282
283 LOG("SubThread: check the block set is inherited");
284 pthread_sigmask(SIG_BLOCK, nullptr, &oldmask);
285 if (!sigismember(&oldmask, SIGUSR1)) {
286 LOG("initial block set should include SIGUSR1!");
287 return (void*)1;
288 }
289
290 LOG("SubThread: add SIGINT to block set");
291 sigaddset(&sigmask, SIGINT);
292 int rt = pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
293 EXPECT_EQ(rt, 0);
294
295 LOG("SubThread: check the new block set");
296 sigemptyset(&oldmask);
297 pthread_sigmask(SIG_UNBLOCK, nullptr, &oldmask);
298 if (!sigismember(&oldmask, SIGINT)) {
299 LOG("failed to add SIGINT to block set!");
300 return (void*)1;
301 }
302 if (!sigismember(&oldmask, SIGUSR1)) {
303 LOG("SIGUSR1 should still in block set!");
304 return (void*)1;
305 }
306 return nullptr;
307 }