linux SIGBUS 总线错误

来源:互联网 发布:顾比均线源码带买卖点 编辑:程序博客网 时间:2024/04/30 02:56

http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=1988350&ordertype=1

用mmap映射两个文件,然后把一个文件的内容复制到另一个文件
采用的是memcpy函数
但是使用这个函数出现了总线错误
我把两个映射的地址和长度都输出来了
请高手给分析一下。
输出结果:
file size = 18
src = 0xb7fa9000
dst = 0xb7fa8000
总线错误

  1. #include <stdio.h>
  2. #include <fcntl.h>
  3. #include <sys/mman.h>
  4. #include <sys/stat.h>
  5. #include <sys/types.h>
  6. #include <stdlib.h>
  7. #include <string.h>

  8. int main(int argc,char *argv[])
  9. {
  10.         int fdin,fdout;
  11.         void *src,*dst;

  12.         struct stat statbuf;

  13.         if(argc != 3)
  14.         {
  15.                 printf("usage : %s <fromfile> <tofile>\n",argv[0]);
  16.                 return 1;
  17.         }
  18.         if((fdin = open(argv[1],O_RDONLY)) == -1)
  19.         {
  20.                 printf("can't open file %s\n",argv[1]);
  21.                 return 1;
  22.         }
  23.         if((fdout = open(argv[2],O_RDWR | O_CREAT | O_TRUNC,0644)) == -1)
  24.         {
  25.                 printf("can't create file %s\n",argv[2]);
  26.                 return 1;
  27.         }
  28.         if(fstat(fdin,&statbuf) < 0)
  29.         {
  30.                 printf("fstat error.\n");
  31.                 return 1;
  32.         }
  33.         printf("file size = %d\n",statbuf.st_size);
  34.         if(lseek(fdout,statbuf.st_size - 1,SEEK_SET) == -1)
  35.         {
  36.                 printf("set file size error.\n");
  37.                 return 1;
  38.         }
  39.         printf("file size = %d\n",statbuf.st_size);
  40.         if(lseek(fdout,statbuf.st_size - 1,SEEK_SET) == -1)
  41.         {
  42.                 printf("set file size error.\n");
  43.                 return 1;
  44.         }
  45.         if((src = mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,fdin,0)) == MAP_FAILED)
  46.         {
  47.                 printf("mmap error for fdin.\n");
  48.                 return 1;
  49.         }
  50.         printf("src = 0x%x\n",src);
  51.         if((dst = mmap(0,statbuf.st_size,PROT_READ | PROT_WRITE,MAP_SHARED,fdout,0)) == MAP_FAILED)
  52.         {
  53.                 printf("mmap error for fdout.\n");
  54.                 return 1;
  55.         }
  56.         printf("dst = 0x%x\n",dst);
  57.         memcpy(dst,src,statbuf.st_size);
  58.         close(fdin);
  59.         close(fdout);
  60.         exit(0);
  61. }
----------------------------------------------------------
#include<unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>

int main(int argc,char*argv[])
{
&nbsp;int fdin,fdout;
&nbsp;void* src;
&nbsp;void* dst;
&nbsp;struct stat statbuf;

if(argc != 3)
{
&nbsp;&nbsp;&nbsp;&nbsp;printf("please input two file!\n");
&nbsp;&nbsp;&nbsp;&nbsp;exit(1);
}

if((fdin=open(argv[1],O_RDONLY))<0)/*打开原文件*/
&nbsp;&nbsp;&nbsp;&nbsp;perror(argv[1]);

if((fdout=open(argv[2],O_RDWR|O_CREAT|O_TRUNC))<0)/*创建并打开目标文件*/
&nbsp;&nbsp;&nbsp;&nbsp;perror(argv[2]);

if(fstat(fdin,&statbuf)<0)/*获得文件大小信息*/
&nbsp;&nbsp;&nbsp;&nbsp;printf("fstat error");

if(lseek(fdout,statbuf.st_size-1,SEEK_SET)==-1)/*初始化输出映射存储区*/
&nbsp;&nbsp;&nbsp;&nbsp;printf("lseek error");

if(write(fdout,"1",1)!=1)
&nbsp;&nbsp;&nbsp;&nbsp;printf("write error");

if((src=mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,fdin,0))==MAP_FAILED)
&nbsp;&nbsp;&nbsp;&nbsp;printf("mmap error");

if((dst=mmap(0,statbuf.st_size,PROT_READ|PROT_WRITE,MAP_SHARED,fdout,0))==MAP_FAILED)
&nbsp;&nbsp;&nbsp;&nbsp;printf("mmap error");

&nbsp;memcpy(dst,src,statbuf.st_size);/*复制映射存储区*/
&nbsp;munmap(src,statbuf.st_size);/*解除输入映射*/
&nbsp;munmap(dst,statbuf.st_size);/*解除输出映射*/

&nbsp;close(fdin);
&nbsp;close(fdout);

&nbsp;return 0;
}[/code]
lz的问题只是没加红色的哪条语句....
如果加,当写入数据的时候会遇到文件结束符,产生SIGBUS信号
------------------------------------------------------------------------------------------------
用ftruncate函数可以代替lseek函数更好些
--------------------------
但是从LZ输出的的src和dst地址来看
它是页对齐的
只是lseek函数使用不是很正确
在lseek之后加上一条I/O操作的话 就正确了
这个bus error 似乎在这里面得不到很好体吧
不知道为什么会报bus error错误
----------------------------------------------------------------------
转载一段:
(1)总线错误:
书上的一段程序:
union { char a[10];
        int i;
      }u;
int *p = (int *)&(u.a[1]);
*p = 17;
书上是说,这段代码会引发总线错误(bus error),但是我不论在ubuntu Linux上调试还是在Window XP(TC)中调试,均未有报错。后来在网上搜索,很多人提到是因为SUN操作系统的原因。
摘录一点书上关于总线错误的描述:
总线错误几乎都是由未对齐的读或写引起的。它之所以称为总线错误,是因为出现未对齐的内存访问请求时,被阻塞的组件就是地址总线。对齐(alignment)的意思就是数据项只能存储在地址是数据项大小的整数倍的内存位置上。在现代的计算机架构中,尤其是RSIC架构,都需要数据对齐,因为与任意的对齐有关的额外操作会是整个内存系统更大更缓慢。通过迫使每个内存访问局限在一个Cache行或一个单独的页面内,可以极大的简化(并加速)如Cache控制器和内存管理单元这样的硬件。
我们表达“数据项不能跨越页面或Cache边界”的规则的方法多少有些间接,因为我们用地址对齐这个术语陈述这个问题。页和Cache的大小是经过精心设计的,这样只要遵循对齐规则就可以保证一个原子数据项不会跨越一个页或Cache块的边界。
这是c专家编程上说的
----------------------------------------------------------------------------------------------
原帖由 eclipse_2 于 2009-4-6 20:19 发表
虽然是bus error
如果没有是因为地址没有对齐的话 memcpy应该会自己处理的
我调试了下 好象是lseek函数用的有问题
你可以先查看一下你新创建的那个文件的大小是多少
stat filename

你也就是lseek了一个 ...
------------------------------------------------
虽然是bus error
如果没有是因为地址没有对齐的话 memcpy应该会自己处理的
我调试了下 好象是lseek函数用的有问题
你可以先查看一下你新创建的那个文件的大小是多少
stat filename

你也就是lseek了一个空洞 但是并引起i/o操作
也就是说如果lseek之后没有发生i/o操作时,lseek只是把偏移量给改了一下
并没有在磁盘上分配存储区
而你的文件是新建的 存储的空间长度为0 lseek之后还是为0
把mmap到系统的线性地址空间,然后进行复制的话就会出错

所以建议LZ在lseek之后进行一个I/O操作,这样就会把lseek跳过的长度给你分配磁盘存储区的
这样的话应该就没有问题了
我在我机器上试过了
-------------------------------------------------------------------


0 0
原创粉丝点击