CSAPP 小 shell 实验室:卡在 sigprocmask

问题描述 投票:0回答:1

我正在尝试 CSAPP 中的小型 shell 实验室。但是当我输入命令行时,我的代码卡住了。

steven@Steven:/mnt/f/大学/CSAPP/cmu15213/shlab-handout$ ./tsh
tsh> 123
tsh> 123: command not found
123
123
123
^\Terminating after receipt of SIGQUIT signal
steven@Steven:/mnt/f/大学/CSAPP/cmu15213/shlab-handout$ 

实验室链接:

我通过添加

-Og -g
修改了Makefile并尝试使用GDB和VSCode进行调试。

我发现程序卡在

sigprocmask
上。如下图所示,如果我点击“Step Over”,它会继续运行,永远不会停止。

我复制了相关代码并单独运行,它运行正常。

我在 WSL 和虚拟机中对此进行了测试,并且两者都表现出相同的行为。

c linux debugging gdb system-calls
1个回答
0
投票

如果我单击“Step Over”,它会继续运行并且永远不会停止。

我转载了。那么让我们看看发生了什么。

gdb -q ./tsh
(gdb) break tsh.c:191
(gdb) b tsh.c:191
Breakpoint 1 at 0x40156a: file tsh.c, line 191.

(gdb) run
Starting program: /tmp/tsh
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
tsh> aaa
[Detaching after fork from child process 182]

aaa: command not found
Breakpoint 1, eval (cmdline=0x7fffffffd930 "aaa\n") at tsh.c:191
191         sigprocmask(SIG_SETMASK, &prev, NULL);
(gdb) n

此时一切都挂了,所以我们必须陷入

sigprocmask
,对吗?

事实上,我们不是。

^C
Program received signal SIGINT, Interrupt.
0x00007ffff7eb5c37 in __GI___wait4 (pid=-1, stat_loc=0x7fffffffcd5c, options=3, usage=0x0)
    at ../sysdeps/unix/sysv/linux/wait4.c:30
30        return SYSCALL_CANCEL (wait4, pid, stat_loc, options, usage);
(gdb) bt
#0  0x00007ffff7eb5c37 in __GI___wait4 (pid=-1, stat_loc=0x7fffffffcd5c, options=3, usage=0x0)
    at ../sysdeps/unix/sysv/linux/wait4.c:30
#1  0x0000000000401a02 in sigchld_handler (sig=17) at tsh.c:383
#2  <signal handler called>
#3  __GI___pthread_sigmask (how=2, newmask=<optimized out>, oldmask=0x0) at pthread_sigmask.c:43
#4  0x00007ffff7e18d8d in __GI___sigprocmask (how=<optimized out>, set=<optimized out>, oset=<optimized out>)
    at ../sysdeps/unix/sysv/linux/sigprocmask.c:25
#5  0x0000000000401583 in eval (cmdline=0x7fffffffd930 "aaa\n") at tsh.c:191
#6  0x000000000040142d in main (argc=1, argv=0x7fffffffde68) at tsh.c:149

现在我们看看“实际上”发生了什么。 sigprocmask 解锁

SIGCHLD
,从而导致在
 
sigprocmask 即将返回之前立即 传送该信号。这反过来会调用 sigchld_handler
反复
 在永无休止的循环中调用 
waitpid
为什么循环不终止?因为代码期望 
waitpid

在没有子节点时返回

0

,但这是不正确的:在这种情况下 
waitpid
 返回 
-1
以下修复使 
tsh

按预期工作:

 diff -u tsh.c.orig tsh.c
--- tsh.c.orig  2024-01-20 21:42:47.915401415 -0800
+++ tsh.c       2024-01-20 21:43:20.145996657 -0800
@@ -383,7 +383,7 @@
         pid = waitpid(-1, &status, WNOHANG | WUNTRACED);

         // 如果没有僵尸进程,则退出
-        if (pid == 0)
+        if (pid == 0 || pid == -1)
             return;

         // 如果子进程终止导致waitpid从阻塞中恢复

./tsh tsh> aaa aaa: command not found tsh> bbb bbb: command not found tsh>
    

© www.soinside.com 2019 - 2024. All rights reserved.