Board logo

标题: 使用 DrMemory 发现内存编程错误(2) [打印本页]

作者: look_w    时间: 2018-6-18 12:39     标题: 使用 DrMemory 发现内存编程错误(2)

DrMemory 报告解读细节内存非法访问DrMemory 认为任何对未分配内存区域的读写都是非法的。在 Linux 中,应用程序可以用以下几个方式分配内存:
非法访问就是对以上三种方法分配的内存区域之外进行的访问。常见的问题包括 buffer overflow、数组越界、读写已经 free 的内存、堆栈溢出等等。让我们测试下面这个问题程序。
清单 2,存在非法访问的例子程序
1
2
3
4
5
6
7
8
9
10
1:  int main()
2:  {
3:    char *ptr;
4:    int i;
5:    char *x = malloc(8);
6:    char c = *(x+8);   //buffer overlow
7:    free(x);
8:    c = *x;  //read free memory
9:    return 0;
10: }




Buffer overflow
例子程序的第 5 到 6 行存在 buffer overflow。在内存中,buffer 的分布如下图所示:
图 2. Buffer 分布访问 x+8 将产生一个非法内存访问。对此,Dr Memory 将给出如下的错误信息:
1
2
3
4
5
6
7
8
9
Error #1: UNADDRESSABLE ACCESS:
reading 0x0804a020-0x0804a021 1 byte(s)
# 0 t!main          [/home/DrMem/t.c:9]
# 1 libc.so.6<nosyms>!?
# 2 t!_start
Note: elapsed time = 0:00:00.133 in thread 13971
Note: refers to 1 byte(s) beyond last valid byte in prior malloc
Note: prev lower malloc:  0x0804a018-0x0804a020
Note: instruction: movzx  (%eax) -> %eax




首先用大写的单词 UNADDRESSABLE ACCESS 表明这是一个非法访问错误。接着,“reading 0x0804a020-0x0804a021 1    byte(s)”表示这是一个非法读,读取的范围为 0x0804a020 到 0x0804a021,一共读了 1 个 byte。接下来的三行是调用堆栈信息,可以方便地看到错误发生在哪个源文件的哪一行(程序 t 需要在用 gcc 编译的时候给定-g 选项)。此外 DrMemory 还给出了一些辅助的错误信息。比如:
错误发生的时间:Note: elapsed time = 0:00:00.133 in thread 13971。这表明错误是程序开始的第 0.133 秒后发生的,有些情况下,人们可以根据这个时间进行辅助判断。
错误细节:Note: refers to 1 byte(s) beyond last valid byte in prior malloc。这里给出了错误的详细信息,如前所述,造成非法访问的可能很多,在本例中是 buffer overflow,因此这里的详细信息可以帮助我们了解非法访问的具体原因。
Note: prev lower malloc:  0x0804a018-0x0804a020。这里给出了 overflow 之前的合法内存地址,有些情况下对于查错 有一定的帮助。
Note: instruction: movzx  (%eax) -> %eax。这里给出的是造成错误的具体指令。
访问已释放内存例子程序的第 7 行将内存 x 释放,之后再读取该内存即为错误。对于此类错误,错误信息如下所示:
1
2
3
4
5
6
7
8
9
Error #2: UNADDRESSABLE ACCESS:
reading 0x0804a018-0x0804a019 1 byte(s)
# 0 t!main                         [/home/DrMem/t.c:13]
# 1 libc.so.6<nosyms>!?
# 2 t!_start
Note: elapsed time = 0:00:01.159 in thread 16384
Note: 0x0804a018-0x0804a019 overlaps
memory 0x0804a018-0x0804a020 that was freed
Note: instruction: movzx  (%eax) -> %eax




一些运行选项可以让 DrMemory 的报告更加易读,或者给出更有指导性的信息。
-delay_frees_stack 选项的影响
仍然使用前面的例子,在运行 DrMemory 的时候给定-delay_frees_stack 选项:
1
drmemory.pl –delay_fress_stack -- ./t




现在打开 DrMemory 的 result 文件,将看到关于访问以释放内存的错误信息更加丰富了:
1
2
3
4
5
6
7
8
9
10
11
12
13
Error #2: UNADDRESSABLE ACCESS:
reading 0x0804a018-0x0804a019 1 byte(s)
# 0 t!main                                          [/home/DrMem/t.c:13]
# 1 libc.so.6<nosyms>!?
# 2 t!_start
Note: elapsed time = 0:00:01.176 in thread 24378
Note: 0x0804a018-0x0804a019 overlaps
memory 0x0804a018-0x0804a020
that was freed here:
Note: # 0 t!main                        [/homeDrMem/t.c:13]
Note: # 1 libc.so.6<nosyms>!?
Note: # 2 t!_start
Note: instruction: movzx  (%eax) -> %eax




多了三行 Note:信息,指明内存释放的代码行。这个特性在很多情况下都十分有用。因为程序可能在释放内存之后很久才对其进行读写,如果不指出释放的地方,查找错误原因还要很费一番工夫。有了这额外信息,我们立即就可以知道程序是在 t.c 的第 13 行将内存释放掉了。
-brief 选项的影响
采用    –delay_fress_stack之后,虽然信息更丰富了,但天下没有免费的午餐,这样也有一个缺点,即最终报告变得不易阅读了。因此您还可以使用-brief 选项来简化输出。
1
2
3
4
5
6
7
8
9
10
drmemory.pl –delay_fress_stack -- ./t
。。。
Error #3: UNADDRESSABLE ACCESS: reading 1 byte(s)
# 0 t!main                     [/home/DrMem/t.c:14]
# 1 libc.so.6<nosyms>!?
# 2 t!_start
Note: refers to memory that was freed here:
Note: # 0 t!main              [/home/DrMem/t.c:14]
Note: # 1 libc.so.6<nosyms>!?
Note: # 2 t!_start




不再输出类似 elapseTime 等信息,从而简化错误信息,使之更加容易阅读。也许您并不认为上述输出更加容易阅读,嗯,您可以不使用这个选项。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0