诡异程序分析
运行环境 centos, 64bit
先上代码:
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define BUF_SIZE 10
int
main(int argc, char *argv[])
{
int fd, res;
off_t offset;
char buf[BUF_SIZE];
fd = open("./story", O_RDWR | O_APPEND);
if (fd == -1) {
perror("open error");
exit(1);
}
offset = lseek(fd, 5, SEEK_CUR);
if (offset == -1) {
perror("lseek error");
exit(1);
}
res = read(fd, buf, BUF_SIZE);
if (res == -1) {
perror("read error");
exit(1);
}
write(STDOUT_FILENO, buf, strlen(buf));
offset = lseek(fd, 0, SEEK_CUR);
if (offset == -1) {
perror("lseek error");
exit(1);
}
memset(buf, 0, BUF_SIZE);
strcpy(buf, "my name is puppy");
res = write(fd, buf, strlen(buf));
if (res == -1) {
perror("write error");
exit(1);
}
close(fd);
return 0;
}
程序输出:

首先,输出一个@,多输出了一个。这个很好解决,write(STDOUT_FILENO, buf, strlen(buf)), 使用strlen计算
字符长度,必须要有\0,然而read读的时候,不会在末尾设置\0, 所以,write的时候,写入size计算错误,改写为:
write(STDOUT_FILENO, buf, res), res 即为read读取的长度。
其次:my name is puppy 输出在屏幕上,而没有在文件story中。这一点比较诡异,看buf大小[BUF_SIZE], 即10.
而,写入的字符串远远大于了10, 这样,冲刷了栈的内容,导致fd被改写啦,fd变成了0, 所以写入了屏幕上。
解决方法:第一次发现这类函数的不安全,所以,采用strncpy,这样,就保证了栈内容不会异常。
修正后代码:
1 #include <fcntl.h> 2 #include <string.h> 3 #include <unistd.h> 4 #include <stdlib.h> 5 #include <stdio.h> 6 7 #define BUF_SIZE 10 8 9 int 10 main(int argc, char *argv[]) 11 { 12 int fd, res; 13 off_t offset; 14 char buf[BUF_SIZE]; 15 16 fd = open("./story", O_RDWR | O_APPEND); 17 if (fd == -1) { 18 perror("open error"); 19 exit(1); 20 } 21 22 offset = lseek(fd, 5, SEEK_CUR); 23 if (offset == -1) { 24 perror("lseek error"); 25 exit(1); 26 } 27 28 29 res = read(fd, buf, BUF_SIZE); 30 if (res == -1) { 31 perror("read error"); 32 exit(1); 33 } 34 35 write(STDOUT_FILENO, buf, res); 36 37 offset = lseek(fd, 0, SEEK_CUR); 38 if (offset == -1) { 39 perror("lseek error"); 40 exit(1); 41 } 42 43 memset(buf, 0, BUF_SIZE); 44 strncpy(buf, "my name is puppy", BUF_SIZE); 45 46 res = write(fd, buf, strlen(buf)); 47 if (res == -1) { 48 perror("write error"); 49 exit(1); 50 } 51 52 close(fd); 53 54 return 0; 55 }
再者,查看story文件:
初始状态:

运行程序后:

仍然有一个@,典型是写入的时候,仍然使用了strlen来计算长度。但是,本行没有结束,为什么另起一行呢。
再次运行程序:

很奇怪,没有另开一行,这就让人很纳闷啦。
打开文件,切入编辑模式,即按“i",然后立即保存,再次运行程序,输出如下:

查看刚刚此文件的ASCLL码内容如下:

打开,按'i', 立即保存,如下:

多了一个\n, 也就是说,vim编辑器处于编辑状态时,自动会在行尾加换行,所以导致上述奇怪内容的出现。
另外,该题对应于AUPE 第三章 课后习题3.6,当以append方式打开后,write的时候,直接将指针切换到文章最后,然后
开始写,不理会之前指针的位置。

浙公网安备 33010602011771号