为什么我得到一个“stack smashing detected”错误,除非我存储文件描述符?

li9yvcax  于 2023-10-16  发布在  其他
关注(0)|答案(1)|浏览(240)

我正在尝试一些I/O系统调用:从现有文件中读取2个字节,将它们放入缓冲区,然后将这些字节写入另一个空的现有文件。

// read_write.c
int open(char *filename, int access);
long read(int fd, void *buffer, unsigned long byte_count);
long write(int fd, void *buffer, unsigned long byte_count);
int close(int fd);

// assume both `source.txt` and `target.txt` exist.
int main(void) {
    char buffer;

    // open for reading only (fd = 3).
    open("source.txt", 0); 

    // open for writing only (fd = 4).
    open("target.txt", 1); 

    // read 2 bytes from fd = 3 to buffer.
    read(3, &buffer, 2);

    // reads 2 bytes from buffer to fd = 4.
    write(4, &buffer, 2);

    // close both file descriptors 3 and 4.
    close(3);
    close(4);

    return 0;
}

当我编译并运行上面的程序时,我得到以下错误:

$ gcc read_write.c && ./a.out 
*** stack smashing detected ***: terminated
Aborted (core dumped)
$ cat target.txt 
ab
$

正如你所看到的,程序从一个文件读到另一个文件,但我试图找出这个错误的原因。关于stack smashing detected有这样的解释,它说它通常会发出缓冲区溢出错误的信号,但我不明白如何将文件描述符存储在变量中会消除这样的错误。
当我存储两个文件描述符(例如,int sfd = open("source.txt", 0);)时,尽管在程序的其他任何地方都没有使用它们,但它可以正常工作。

4ktjp1zp

4ktjp1zp1#

看似正确的结果是未定义行为的一种方式。
正如注解中所写的,您可以看到对read(3, &buffer, 2);中的buffer的越界访问导致的未定义行为。
如果这覆盖了编译器生成的堆栈保护代码所使用的某些模式,则会导致您得到的错误。
int sfd = ...;在堆栈上分配另一个变量,用于扩展可用的堆栈内存。我猜它正好使用buffer之后的内存。在这种情况下,变量sfd或变量之间可能的填充字节将被您的越界访问覆盖,从而保持堆栈保护模式不变。

相关问题