所以,我发现了问题。
这个问题基本上是由于转移到integer 而不是long。这在 Tcl 中是在 tclUnixChan.c 中完成的,同时计算需要在 tsdPtr->checkMasks 中修改的索引和位:
index = fd/(NBBY*sizeof(fd_mask));
bit = 1 << (fd%(NBBY*sizeof(fd_mask)));
位线需要是1L << 而不是1 <<。 fd_mask 本身是一个long 并在sys/types.h 中定义。这只是问题的一部分。
sys/types.h 还包含在设置或清除 fd_masks 中的位时应使用的宏定义(FD_CLR、FD_SET、FD_ISSET、FD_ZERO)。
此问题已在版本 8.4.9 中部分修复,并在版本 8.4.20 中完全修复。
修复是通过使用types.h 中定义的宏而不是手动操作fd_mask 位来完成的。
8.4.9 版本中引入的部分修复在tclUnixNotfy.c 中:
- struct
SelectMasks 已创建,它使用在 types.h 中定义的 fd_set 类型
- ThreadSpecificData
checkMasks 和 readyMasks 字段从 fd_mask 数组更改为 SelectMasks
-
在
Tcl_CreateFileHandler、Tcl_DeleteFileHandler、Tcl_WaitForEvent、NotifierThreadProc 中使用的用于处理掩码的index 和bit 变量被删除,FD_CLR、FD_SET、FD_ISSET、@98765432 被使用而是。
-
Tcl_WaitForEvent 将readyMasks 分配给checkMasks,而不是在调用select 之前使用memcpy
- 现在删除了在调用 select 时将
readyMasks 转换为 SELECT_MASK * 并且 & 运算符现在直接用于 fd_set 类型的 SelectMasks 结构元素。
版本8.4.20 中引入的修复的另一部分是tclUnixChan.c:
-
index 和 bit 在 TclUnixWaitForFile 中用于处理掩码的变量已被删除,而使用 FD_CLR、FD_SET、FD_ISSET、FD_ZERO 代替。
-
使用
fd_set 类型而不是在TclUnixWaitForFile 中创建fd_mask 数组。
- 现在删除了在调用 select 时将掩码转换为
SELECT_MASK *,并且现在可以直接对创建的 fd_set 变量使用 & 运算符。
根据8.4.9 和8.4.20 中所做的更改,我已经修补了我当前版本的8.4.3,因为我没有升级整个Tcl 版本的灵活性。
我关于为什么打开一个新的 shell 窗口可以使该工具工作的理论:
由于在错误大小的容器中移动并使用具有奇怪长度3*MASK_SIZE 的memcpy 导致内存损坏,我最终指向的fd 与窗口管理相关,因此为什么要打开一个新外壳由于我指向的那些错误的fd 频道上有数据,因此选择返回非零值。
使我得出这个理论的是strace 输出以及lsof 输出:
strace 挂起时的输出重复了以下部分:
poll([{fd=4, events=POLLIN}, {fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 2, 0) = 0 (Timeout)
recvfrom(4, 0x80e21f4, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
recvfrom(4, 0x80e21f4, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=4, events=POLLIN}, {fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 2, 0) = 0 (Timeout)
recvfrom(6, 0x8380d64, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
select(36, [3 6], [], [], {0, 0}) = 0 (Timeout)
recvfrom(6, 0x8380d64, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
recvfrom(6, 0x8380d64, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
select(36, [3 6], [], [], {0, 0}) = 0 (Timeout)
recvfrom(6, 0x8380d64, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=4, events=POLLIN}, {fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 2, 0) = 0 (Timeout)
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {0x4c3cd70, [CHLD], SA_RESTORER|SA_RESTART|SA_SIGINFO, 0x37eec0f790}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
strace 打开新的 shell 选项卡时的输出更改为:
poll([{fd=4, events=POLLIN}, {fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 2, 0) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "X\1\366\371\264\300\7=\3\0\22\0\10\377\0\0\26\1\26\1\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096, 0, NULL, NULL) = 256
recvfrom(4, 0x80e21f4, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
recvfrom(4, 0x80e21f4, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=4, events=POLLIN}, {fd=5, events=POLLIN|POLLPRI|POLLRDNORM|POLLRDBAND}], 2, 0) = 0 (Timeout)
recvfrom(6, "X\1\321/\264\300\7=\3\0\22\0\10\377\0\0\26\1\26\1\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096, 0, NULL, NULL) = 256
recvfrom(6, 0x8380d64, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
select(36, [3 6], [], [], {0, 0}) = 1 (in [3], left {0, 0})
recvfrom(6, 0x8380d64, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
read(35, "", 4096) = 0
close(35) = 0
lsof 输出显示频道4 和6 的以下内容:
myexec 13626 aymansalah 4u IPv4 1607796326 0t0 TCP rhe6x64:38787->nx-svr:7016 (ESTABLISHED)
myexec 13626 aymansalah 6u IPv4 1607837231 0t0 TCP rhe6x64:38788->nx-svr:7016 (ESTABLISHED)
频道4 和6 是将我的机器连接到NX 服务器的频道。
参考资料: