在研究CSAPP中的家庭作业(job)问题8.25时,我提到了它的解决方案,在https://dreamanddead.github.io/CSAPP-3e-Solutions/.提供的解决方案包括以下C代码:

#include <stdio.h>
#include "csapp.h"

sigjmp_buf buf;

void handler(int sig) {
  /* jump */
  siglongjmp(buf, 1);
}

char* tfgets(char* s, int size, FILE* stream) {
  char* result;

  if (!sigsetjmp(buf, 1)) {
    alarm(5);
    if (signal(SIGALRM, handler) == SIG_ERR)
      unix_error("set alarm handler error");
    return fgets(s, size, stream);
  } else {
    /* run out of time */
    return NULL;
  }
}

tfgets功能是具有超时功能的fgets.然而,使用siglong jmp跳出IO操作的安全性引起了人们的关注.

使用sigLongjMP中断IO操作并突然退出是否安全?

我找不到任何关于堆栈溢出的文档或相关问题.

推荐答案

一百零二 从这个操控者做siglongjmp分是not安全的.您可以 destruct fgets正在操作的流的状态.

让信号处理程序设置一个全局变量(例如volatile int alarm_fired;)),而不是执行sigsetjmp/siglongjmp.

然后,如果处理程序触发,则fgets应返回NULL,errno应设置为EINTR.

您可以(安全地)判断返回值和errno值.你也可以查alarm_fired.


However ...

如果没有siglongjmp,fgets将(至少在Linux/glibc下)吸收信号.

而且,即使它确实立即返回,也不清楚将errno would设置为多少(例如,EINTREAGAIN).

因此,您可能必须配置流以允许此操作.一些可能性:

  1. 将基础文件描述符设置为非阻塞
  2. 使用cfmakeraw
  3. 使用FIONREAD ioctl.
  4. fileno(stream)上使用select和/或poll.
  5. 省略流I/O,直接使用read,可能与上面的一些其他项目一起使用.

seems主要用于从TTY设备(例如stdin)或管道/插座而不是文件获得超时.在我看来,在这些情况下,read似乎是更好的 Select .


Side note:个 你有种族问题.

在执行alarm之后设置信号处理程序(设置为signal).在系统负载较重的情况下,信号可能会在您有机会设置处理程序之前触发.

alarm放在signal电话后面.

C++相关问答推荐

为指针 struct 创建宏

设计处理各种数据类型的方法和数据 struct

从C函数调用asm函数时生成错误的BLX指令(STM32H753上的gcc)

Ebpf内核代码:permission denied:invalid access to map value

C/SDL程序,渲染不使用我的渲染器

将 typewriter LF打印到Windows终端,而不是隐含的CR+LF

当execvp在C函数中失败时杀死子进程

为什么memcpy进入缓冲区和指向缓冲区的指针工作相同?

如何在C++中处理按键

在每种If-Else情况下执行语句的最佳方式

用C语言计算文本文件中的整数个数

将多项式从文件.txt加载到终端时出现问题

OSDev--双缓冲重启系统

生产者消费者计数器意外输出的C代码

在运行时判断C/C++指针是否指向只读内存(在Linux操作系统中)

意外的C并集结果

一元运算符

C23 中的 [[reproducible]] 和 [[unsequenced]] 属性是什么?什么时候应该使用它们?

无法在 C 中打开文本文件,我想从中读取文本作为数据并将其写入数组

char* 上的 free() 被 valgrind 识别为无效