GDB外壳中的流程替换问题

时间:2019-11-06 13:00:09

标签: bash gdb

以下代码 readTwice.c 从标准输入读取两次:

int main()
{
    char s[8]={0};
    read(0, (void *)s, (size_t) 3);
    read(0, (void *)(s + 4), (size_t) 3);
    for (int i = 0; i < 8; i++)
        printf("%d: 0x%x\n", i, s[i]);
    return 0;
}

我的目标是在调试相应的二进制文件时,为第一个read()提供第一个文件 a (例如,由echo a > a创建),第二个read()并带有第二个文件 b (例如,由echo b > b创建)。

在GDB外部,以下bash 5.0命令具有预期的效果:

$ ./readTwice < <(cat a;cat b)
0: 0x61
1: 0xa
2: 0x0
3: 0x0
4: 0x62
5: 0xa
6: 0x0
7: 0x0

但是,当在GDB 8.2.1中以相同的进程重定向运行二进制文件时,第一个read()调用也会读取第二个文件的开头:

$ gdb -q readTwice
Reading symbols from readTwice...(no debugging symbols found)...done.
(gdb) run < <(cat a;cat b)
Starting program: /home/av/root-me/ch77/readTwice < <(cat a;cat b)
0: 0x61
1: 0xa
2: 0x62
3: 0x0
4: 0xa
5: 0x0
6: 0x0
7: 0x0
[Inferior 1 (process 4710) exited normally]
(gdb) 

您能帮助我理解此行为和/或告诉我有关具有预期效果的命令吗?

1 个答案:

答案 0 :(得分:0)

程序输入包含4个字符:

'a' '\n' 'b' '\n'

在程序内部,您使用两个reads

read(0, (void *)s, (size_t) 3);
read(0, (void *)(s + 4), (size_t) 3);

read不能完全读取 3个字符。它最多读取3个字符,并返回读取的字符数,请参阅man read(2)。我假设默认情况下STDIN_FILENO在您的平台上处于阻止状态,因此它应读取至少1个字符。

可能的结果:

  • read都读取1个字节。 s将有{'a',0,0,0,'\n',0,0,0}。输入中有2个未读字节。
  • 第一个read读取1个字节,第二个读取3个字节。 s将有{'a',0,0,0,'\n','b','\n',0}
  • 第一个read读取3个字节,第二个读取1个字节。 s将有{'a','\n','b',0,'\n',0,0,0}。这是您在gdb中观察到的输出。
  • 第一个read读取2个字节,第二个读取2个字节。 s将有{'a','\n',0,0,'b','\n',0,0}。这是您在shell中运行时观察到的输出。
  • 希望您现在就明白了。

您的操作系统很可能在平台上以行缓冲方式在read上实现了STDIN_FILENO,因此,最有可能出现的两个结果就是您正在观察的结果。