| yuxq 回复于:2003-08-08 09:39:41
|
当申请一块内存以后,如果你指针越界,当他在没有超出你所申请的内存的页的大小时,即使指针越界,也可以使用,但是如果指针超出了你所申请的内存的那页,到了另外一内存页,就会出现segmentation fault (分段故障)
|
| kj501 回复于:2003-08-08 12:56:37
|
自问自答,呵呵!
|
| 蓝色键盘 回复于:2003-08-08 13:07:24
|
[quote:a95f84788c="yuxq"]当申请一块内存以后,如果你指针越界,当他在没有超出你所申请的内存的页的大小时,即使指针越界,也可以使用,但是如果指针超出了你所申请的内存的那页,到了另外一内存页,就会出现segmentation fault (分段故障)[/quote:a95f84788c]
呵呵,你说的有一定的道理,系统按照一定的大小管理内存页面,这个页面的大小也不是固定的哦,有些是4096字节,有些是8194,对于段违例而言,除了于页面的大小有关外,还于内存保护算法有关,这个算法一般能够处理到4自己是否发生违例,遗憾的是,有些系统可能压根没有这个保护措施,例如sco unix,很可能是完全针对页面大小保护。
|
| yuxq 回复于:2003-08-08 14:01:33
|
谢谢斑竹更深入的解释!
|
| alexai 回复于:2003-08-08 14:42:49
|
请试试下面的程序
int main(){
char *p0,*p1,*p2;
p1= malloc(40000); // 在;p0heap分配足够大的一块
p0= malloc(10);
p2= malloc(40000);
*(p0+2*4096)=1;
}
|
| alexai 回复于:2003-08-08 14:56:04
|
解释一下,
分配三块内存区,其中两块足够大,其中一块p0小些,希望malloc将小的那块夹在两块大的中间,这个我没有试过,但是作为例子足够了,然后,用*(p0+2*4096)越界访问,这时候p0+2*4096已经越过了malloc分配的区,而且肯定越过了它所在的页面,,但是,segment fault没有发生。呵呵。但是你把p2=malloc(40000)去掉,segement fault就发生了。
原因呢,因为系统不是因为内存访问超越malloc分配区发生段访问异常,也不是因为越过了页面发生异常,而是因为访问了不存在的页,或者有写保护的页,其他例子嘛:请看:
char * str="I love BSD";
int main(){
*(str+1)='1';
}
一样的会段异常,这是因为str指向的内存区在代码段,这个段的页面是有写保护的。
欢迎指正
|
| alexai 回复于:2003-08-08 14:58:06
|
对不起,后面那个例子搞错了,那个会出现bus error,有兴趣的看看manual吧,要上班了
|
| alexai 回复于:2003-08-08 17:28:13
|
更准确地意思:
seg fault 一般是访问不存在的页面时, 不存在的叶面就是没有被os分配页面的地址空间, 如:进程的第一页,0x0000-0x4095, heap区以上&&stack段以下的区域. 如果进程试图访问这些地址,哪怕是只读, 都会产生seg fault,这个异常是由于MMU在影射地址时找不到页面所致.
还有就是bus error, 一般这是因为进程试图write只读的段segment导致的, 一般只读的段包括: text 段,也就是你的代码区, 全局只读data段,也就是.rodata段, 这个段里放的是字符串常量的内容.
(我还没有搞清楚的是, .data 和.rodata 可以在同一个页面中, cpu如何区同一个页面中一部分是只读的,另一部分是可写的 :()
在有些机器上, 试图读写不对齐的的字段会导致bus error, 但是我试了gcc+BSD+intel,不会产生.
你要是有兴趣的话,可以自己写简单的代码来试试.
如果你幸运, 一个指针跳到了只读段或者不存在页面的地址上,你很快就能知道.
但是你如果不幸运, 一个指针跳了可读写的地方, 嗬嗬, 那就是噩梦了.
所以小心你的指针哦.
|
| odin_free 回复于:2003-08-16 21:43:30
|
segement fault简直太经常出现了
有时在使用指针(数组)的时候,同意alexai的看法
|
| xa_butterfly 回复于:2003-08-17 16:33:32
|
碰到segment fault我头都大了.
我前一段时间就碰到个怪问题:
在aix5.1下编译安装mysql-4.0.14,用了一段时间,有一天突然有些客户端程序一运行就出segment fault的错误,重装也不管用.后来不知怎么就又好了.哎
|
| yuxq 回复于:2003-08-18 08:43:32
|
内存分页的原因
|
| xa_butterfly 回复于:2003-08-18 08:47:28
|
关键问题是怎么避免和解决这类问题啊
|
| youngS 回复于:2003-08-18 13:05:02
|
[quote:ed1708df04="alexai"]解释一下,
分配三块内存区,其中两块足够大,其中一块p0小些,希望malloc将小的那块夹在两块大的中间,这个我没有试过,但是作为例子足够了,然后,用*(p0+2*4096)越界访问,这时候p0+2*4096已经越过了malloc分配?.........[/quote:ed1708df04]
我相信你的这个结论也是随机的,并不是确定的。
malloc分配的内存之间也许是连续的也许不是连续的,因此你用两块大内存来夹一个小内存是不合理的。用malloc分配的同一块内存是连续的,但是不同malloc之间的也许是不连续的,所以你不能这样来做试验。
|
| yuxq 回复于:2003-08-18 13:43:43
|
应该指定申请内存的起始指针测出的结果才是准确的!
|
| youngS 回复于:2003-08-18 14:31:39
|
[quote:802992a751="xa_butterfly"]关键问题是怎么避免和解决这类问题啊[/quote:802992a751]
你申请了多大的内存就使用多大的内存,这样就不会错。
|
| xa_butterfly 回复于:2003-08-18 15:19:54
|
对于我碰到的问题,能给我一个合理的解释吗
|
| alexai 回复于:2003-08-20 17:42:10
|
[quote:ae1dff74e1="youngS"]
我相信你的这个结论也是随机的,并不是确定的。
malloc分配的内存之间也许是连续的也许不是连续的,因此你用两块大内存来夹一个小内存是不合理的。用malloc分配的同一块内存是连续的,但是不同malloc之间的也许是?.........[/quote:ae1dff74e1]
我同意你的看法,我这么做的原因是作为一个例子来说明问题,是不是连续可以看看分配的地址如何。我在BSD上试过了,证明是连续的。
二则要说明的是,seg fault的原因不是因为越过malloc的界或者页的界,而是因为试图访问没有映射vm页的地址空间。
谢谢你的指正。
|
| 蓝色键盘 回复于:2003-08-23 19:22:55
|
[quote:592440b21d="alexai"]请试试下面的程序
int main(){
char *p0,*p1,*p2;
p1= malloc(40000); // 在;p0heap分配足够大的一块
p0= malloc(10);
p2= malloc(40000);
*(p0+2*4096)=1;
}[/quote:592440b21d]
这样的结构是:不论哪种malloc,大多数情况OS会按照存储器管理的页面大小再堆中sbrk一块区域,这个sbrk相当于批发。实际上比你要用的要大一些。然后这些页面便挂接再进程的内存页面表项中。处理的时候,首先是按照页面存储和修改数据,但是保护的措施分为多种情况,
完了再描述,有事情要走了。。。。
|
| ohwww 回复于:2003-10-10 14:00:24
|
老大,走了这么长时间还不回来解释???等ing
|