【问题标题】:Is any operation needed prior to write(fd,...?在 write(fd,...?
【发布时间】:2020-09-04 18:34:53
【问题描述】:

我在下面写了代码

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

int main() {

    int fd = 3;
    char c[100] = "Testing\n";
    ssize_t nbytes = write(fd, (void *) c, strlen(c));
    return 0;
}

编译/链接,并执行

$ ./io
$ ./io 3> io_3.txt

第一行没有输出。第二行给了我文件io_3.txt,其中包含Testing。 这都是预期的行为(我猜)。

即使在我的测试中它产生了预期的输出, 我不确定,为了避免潜在的问题、未定义的行为等,我是否应该在第一个 write 之前做任何事情,比如检查 fd=3 是否正在使用(在这种情况下,如何... @987654321 @ 可能适用),如果它是适当开放的,等等。

出于同样的原因,我不确定是否应该在最后一个 write 之后执行一些操作。

也许我这样做的方式是“无风险”,唯一的潜在问题是没有写入任何内容,我可以通过检查 nbytes 的值来检测...我不知道。

欢迎任何澄清。

【问题讨论】:

  • 您必须传递一个打开的文件描述符。所以通常你会使用opensocket,或任何其他有效的文件描述符。在这种情况下,您依赖于您的 shell 解释器在执行程序之前为您做一些魔术。那不是便携式的。
  • 没有 UB。带有未打开文件描述符参数的系统调用返回EBADF。检查错误(负返回值和 errno)会发现。
  • 将 fd 3 重定向到一个文件是可以的。但是如果 fd 没有打开写,errno 设置为EBADF
  • @PSkocik - 对!即使文本实际写入重定向目标,nbytes 设置为 -1,errno 设置为 EBADF。

标签: c file-descriptor write


【解决方案1】:

如果您编写这样的程序,在没有打开 fd 3 的情况下执行它是一个使用错误。通常,在没有自己打开它们的情况下,唯一应该按数字使用的文件描述符是 0 (stdin)、1 (stdout) 和 2 (stderr)。如果程序需要将额外的预先打开的文件描述符作为输入,标准习惯用法是在命令行或环境变量上传递 fd 编号,而不是硬编码它们。例如:

int main(int argc, char **argv) {
    if (argc<2 || !isdigit(argv[1][0])) return 1;
    int fd = strtol(argv[1], 0, 0);
    char c[100] = "Testing\n";
    ssize_t nbytes = write(fd, (void *) c, strlen(c));
    return 0;
}

在实践中,如果 fd 3 未打开,那么像您这样的简单程序可能是安全的,写入会失败。但是,一旦您执行任何可能打开文件描述符的操作(可能在实现内部,例如syslog,或打开时区数据的日期/时间函数或消息翻译目录等),fd 3 现在可能会引用到这样一个打开的文件,你错误地尝试写入它。像这样使用文件描述符是一个严重的错误。

【讨论】:

  • 太棒了。据我了解,您的扩展代码从 argv 获取 FD 编号,但仍会写入不保证打开的 FD,因此可能会遇到您描述的相同问题。这是正确的吗?
  • 是的,没错。您可以在执行任何其他操作之前很早就探测(例如使用fcntl(fd, F_GETFD))fd 是否坏,并在错误输入时出错。但这对于一个非平凡的程序来说变得更加困难,因为它可能让 ctor 做一些导致文件描述符被打开的事情。通常,除非它是安全边界(例如 suid 程序),否则我只会相信调用者遵守了合同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-11
  • 2021-05-13
  • 1970-01-01
  • 2013-04-21
相关资源
最近更新 更多