诡异程序分析

运行环境 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 }
View Code

 

再者,查看story文件:

初始状态:

运行程序后:

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

再次运行程序:

很奇怪,没有另开一行,这就让人很纳闷啦。

打开文件,切入编辑模式,即按“i",然后立即保存,再次运行程序,输出如下:

 

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

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

多了一个\n, 也就是说,vim编辑器处于编辑状态时,自动会在行尾加换行,所以导致上述奇怪内容的出现。

 

另外,该题对应于AUPE 第三章 课后习题3.6,当以append方式打开后,write的时候,直接将指针切换到文章最后,然后

开始写,不理会之前指针的位置。

posted @ 2014-01-17 10:25  spch2008  阅读(160)  评论(0)    收藏  举报