You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

strace系统调用顺序与预期不符的原因排查

问题:printf的write系统调用为何晚于open执行?

根据反汇编结果,我原本预期运行测试代码后,strace输出里的write调用会在open之前,但实际显示open先于write执行。想请教是puts以某种方式异步执行write,还是strace对输出进行了重排?

测试代码

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main() {
   close(1);
   printf("Interesting ordering\n");
   int fd = open("temp.txt", O_RDONLY);
   int fd1 = open("temp.txt", O_RDONLY);
}

Strace片段

munmap(0x7fe46ef45000, 115047)          = 0
close(1)                                = 0
newfstatat(1, "", 0x7fffeea1b980, AT_EMPTY_PATH) = -1 EBADF (Bad file descriptor)
getrandom("\x96\xa6\x6b\xd0\x3c\xde\x09\x28", 8, GRND_NONBLOCK) = 8
brk(NULL)                               = 0xb18000
brk(0xb39000)                           = 0xb39000
openat(AT_FDCWD, "temp.txt", O_RDONLY)  = 1
openat(AT_FDCWD, "temp.txt", O_RDONLY)  = 3
write(1, "Interesting ordering\n", 21)  = -1 EBADF (Bad file descriptor)
exit_group(0)                           = ?

main函数反汇编

0000000000401146 <main>:
  401146:   55                      push   %rbp
  401147:   48 89 e5                mov    %rsp,%rbp
  40114a:   48 83 ec 10             sub    $0x10,%rsp
  40114e:   bf 01 00 00 00          mov    $0x1,%edi
  401153:   e8 e8 fe ff ff          call   401040 <close@plt>
  401158:   bf 10 20 40 00          mov    $0x402010,%edi
  40115d:   e8 ce fe ff ff          call   401030 <puts@plt>
  401162:   be 00 00 00 00          mov    $0x0,%esi
  401167:   bf 25 20 40 00          mov    $0x402025,%edi
  40116c:   b8 00 00 00 00          mov    $0x0,%eax
  401171:   e8 da fe ff ff          call   401050 <open@plt>
  401176:   89 45 fc                mov    %eax,-0x4(%rbp)
  401179:   be 00 00 00 00          mov    $0x0,%esi
  40117e:   bf 25 20 40 00          mov    $0x402025,%edi
  401183:   b8 00 00 00 00          mov    $0x0,%eax
  401188:   e8 c3 fe ff ff          call   401050 <open@plt>
  40118d:   89 45 f8                mov    %eax,-0x8(%rbp)
  401190:   b8 00 00 00 00          mov    $0x0,%eax
  401195:   c9                      leave
  401196:   c3                      ret
解答

既不是puts异步执行write,也不是strace重排了输出,核心原因是C标准库的stdio缓冲区机制:

  • 调用close(1)关闭stdout对应的文件描述符后,执行puts时,C标准库首先会通过newfstatat系统调用检查该文件描述符的状态(从strace输出能看到这个调用返回了EBADF错误)。此时标准库已发现文件描述符无效,但不会立即触发write系统调用,而是将输出内容暂存到stdio的用户态缓冲区中。
  • 直到程序执行即将退出时,C标准库会自动触发所有打开的FILE结构体的缓冲区刷新操作,这时才会调用write系统调用尝试写入数据。而此时两次open调用已经执行完毕,所以strace里会看到write出现在open之后。

验证方法:如果在puts之后手动调用fflush(stdout)强制刷新缓冲区,你会看到write调用会立即出现在open之前,因为缓冲区被提前强制刷新了。

内容的提问来源于stack exchange,提问作者user3882729

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 19:23:20