Linux系统中找出并解决程序错误方法( 三 )



CODE:#include "STDLIB.H"
#include "STDIO.H"
int main(void)
{
char *ptr1;
char *ptr2;
char *chptr;
int i = 1;
ptr1 = malloc(512);
ptr2 = malloc(512);
chptr = (char *)malloc(512);
for (i; i <= 512; i) {
chptr = "S";
}
ptr2 = ptr1;
free(ptr2);
free(ptr1);
free(chptr);
}

清单 4. 内存代码(test2.c)
您可以使用下面的命令来启动 YAMD:

CODE:./run-yamd /usr/src/test/test2/test2
清单 5 显示了在样本程序 test2 上使用 YAMD 得到的输出 。YAMD 告诉我们在 for 循环中有“越界(out-of-bounds)”的情况 。

CODE:Running /usr/src/test/test2/test2
Temp output to /tmp/yamd-out.1243
*********
./run-yamd: line 101: 1248 Segmentation fault (core dumped)
YAMD version 0.32
Starting run: /usr/src/test/test2/test2
Executable: /usr/src/test/test2/test2
Virtual program size is 1380 K
...
INFO: Normal allocation of this block
Address 0x40025e00, size 512
...
INFO: Normal allocation of this block
Address 0x40028e00, size 512
...
INFO: Normal allocation of this block
Address 0x4002be00, size 512
ERROR: Crash
...
Tried to write address 0x4002c000
Seems to be part of this block:
Address 0x4002be00, size 512
...
Address in question is at offset 512 (out of bounds)
Will dump core after checking heap.
Done.

清单 5. 使用 YAMD 的 test2 输出
MEMWATCH 和 YAMD 都是很有用的调试工具 , 它们的使用方法有所不同 。对于 MEMWATCH , 您需要添加包含文件 memwatch.h 并打开两个编译时间标记 。对于链接(link)语句 , YAMD 只需要 -g 选项 。
Electric Fence
多数 Linux 分发版包含一个 Electric Fence 包 , 不过您也可以选择下载它 。Electric Fence 是一个由 Bruce Perens 编写的 malloc() 调试库 。它就在您分配内存后分配受保护的内存 。如果存在 fencepost 错误(超过数组末尾运行) , 程序就会产生保护错误 , 并立即结束 。通过结合 Electric Fence 和 gdb , 您可以精确地跟踪到哪一行试图访问受保护内存 。Electric Fence 的另一个功能就是能够检测内存泄漏 。
第 2 种情况:使用 strace
strace 命令是一种强大的工具 , 它能够显示所有由用户空间程序发出的系统调用 。strace 显示这些调用的参数并返回符号形式的值 。strace 从内核接收信息 , 而且不需要以任何特殊的方式来构建内核 。将跟踪信息发送到应用程序及内核开发者都很有用 。在清单 6 中 , 分区的一种格式有错误 , 清单显示了 strace 的开头部分 , 内容是关于调出创建文件系统操作(mkfs)的 。strace 确定哪个调用导致问题出现 。

CODE:execve("/sbin/mkfs.jfs", ["mkfs.jfs", "-f", "/dev/test1"], &
...
open("/dev/test1", O_RDWR|O_LARGEFILE) = 4
stat64("/dev/test1", {st_mode=&, st_rdev=makedev(63, 255), ...}) = 0
ioctl(4, 0x40041271, 0xbfffe128) = -1 EINVAL (Invalid argument)
write(2, "mkfs.jfs: warning - cannot setb" ..., 98mkfs.jfs: warning -
cannot set blocksize on block device /dev/test1: Invalid argument )
= 98
stat64("/dev/test1", {st_mode=&, st_rdev=makedev(63, 255), ...}) = 0
open("/dev/test1", O_RDONLY|O_LARGEFILE) = 5
ioctl(5, 0x80041272, 0xbfffe124) = -1 EINVAL (Invalid argument)
write(2, "mkfs.jfs: can"t determine device"..., ..._exit(1)
= ?

清单 6. mkfs 上 strace 的开头部分
清单 6 显示 ioctl 调用导致用来格式化分区的 mkfs 程序失败 。ioctl BLKGETSIZE64 失败 。(BLKGET-SIZE64 在调用 ioctl 的源代码中定义 。) BLKGETSIZE64 ioctl 将被添加到 Linux 中所有的设备 , 而在这里 , 逻辑卷管理器还不支持它 。因此 , 如果 BLKGETSIZE64 ioctl 调用失败 , mkfs 代码将改为调用较早的 ioctl 调用;这使得 mkfs 适用于逻辑卷管理器 。
第 3 种情况:使用 gdb 和 Oops

推荐阅读