免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: shuchi91
打印 上一主题 下一主题

[C] 为什么这种写法不抱错  关闭 [复制链接]

论坛徽章:
0
41 [报告]
发表于 2009-07-13 21:12 |只看该作者
应该是不报错的
你定义的是char*类型,是个指针
指针加上偏移量读取内存的东西只要那里是可以操作的
就不会出错
但是明显你的操作时非常危险的

论坛徽章:
0
42 [报告]
发表于 2009-07-14 09:56 |只看该作者
原帖由 beepbug 于 2009-7-11 23:29 发表

对,我们忘了这旮沓了。
最后做实存分配是以4KB页为单位的。我只要1B,它也分配4KB。
1)虚存里数组“越界”了,可实存里还在这4KB页内;
2)虚存里数组“越界”了,在实存里也已超出这4KB页范围。
这两种 ...


在Linux下跟物理内存没有一点点关系,当进入do_page_fault例程以后,内核查看地址是否在某个vma的范围内(find_vma()),如果不存在vma包含了该地址并且访问内存操作来自用户空间,就给该进程发sigseg。

不过的确和4K有关系,创建vma总是PAGE_SIZE的倍数,创建完以后的读访问不会导致分配物理页,但是访试图去读一个非法地址一样会触发sigseg。

[ 本帖最后由 vupiggy 于 2009-7-14 03:03 编辑 ]

论坛徽章:
0
43 [报告]
发表于 2009-07-14 10:11 |只看该作者
只有访问非法地址才会报错,由于是按照4K分配的,那么该页面内的地址都是合法的,即使没有用malloc分配。

论坛徽章:
0
44 [报告]
发表于 2009-07-14 11:46 |只看该作者

回复 #1 shuchi91 的帖子

c编译器并不强制要求检查语言层面的指针或则数组下标越界访问.
#include<stdio.h>
#include<stdlib.h>

int
main()
{
      char *xu;
      xu=(char *)malloc(sizeof(char)*100);
      xu[99]='x';
      printf("%c",xu[99]);
      xu[100]='y';
      printf("%c",xu[100]);
      
      char xu2[100];
      xu2[100]='z';
      printf("%c",xu2[100]);
      
      system("pause");
     // return 0;
      
}

编译通过且运行没有错误。
测试环境windows 7 build 7260 ;devc++4.9.9.2

论坛徽章:
0
45 [报告]
发表于 2009-07-15 16:44 |只看该作者
C语言对地址越界之类的错误不检查,所以变成的时候需要我们更加谨慎

论坛徽章:
0
46 [报告]
发表于 2009-07-16 15:54 |只看该作者

地址越界的影响

第一段代码是在堆上越出了xu所分配到的空间,但是并没有越出用户的堆空间,因此运行没有问题。第二段代码是越出了数组xu[]的边界,在函数调用栈上产生了溢出,因为你写到xu[1000],超过了当前的函数调用栈帧,所以没有影响到程序的正常执行。具体的影响取决于执行这段代码时的函数调用关系。如果想看看在栈上地址越界的影响,可以把你的第二段代码改成
for (i = 0; i <= 1000; i++)
xu = 'x';
试试,看程序是否还能继续执行。

论坛徽章:
0
47 [报告]
发表于 2009-07-16 16:06 |只看该作者

上面的代码改错

46楼代码的最后一行应为xu = 'x';

论坛徽章:
0
48 [报告]
发表于 2009-07-16 16:08 |只看该作者

为什么方括号出不来呢?

应是
xu【i】 = ‘x’;

论坛徽章:
0
49 [报告]
发表于 2009-07-16 17:43 |只看该作者
运气,运气而已

论坛徽章:
0
50 [报告]
发表于 2009-07-16 19:00 |只看该作者
原帖由 shuchi91 于 2009-7-9 11:50 发表
25     char *xu;
26     xu=(char *)malloc(100);
27     xu[1000]='x';
28     printf("%c",xu[1000]);


25     char xu[100];
27     xu[1000]='x';
28     printf("%c",xu[1000]);

这两种 ...

上汇编看看 test.c
int main()
{
    char xu[100];
    xu[1000]='x';
    printf("%c\n",xu[1000]);

    return 0;
}
gcc  -S test.c
cat test.s
main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $120, %esp  ->分配栈空间
    andl    $-16, %esp
    movl    $0, %eax
    subl    %eax, %esp
    movb    $120, 880(%ebp) 将 'x' 写到 ebp + 880的位置, 减去 -120 ( subl    $120, %esp)  刚好是 1000的位置,向地址空间的上面走了
    subl    $8, %esp
    movsbl  880(%ebp),%eax
    pushl   %eax  ->   压入xu[1000] 保存的值 : 'x'
    pushl   $.LC0 -> 压入"%c"
    call    printf ->调用printf
    addl    $16, %esp  ->平栈
    movl    $0, %eax -> return 0
    leave
    ret


为啥不出错,因为这是个简单程序,如果作为一个普通的函数, 被多层次调用,那么这个危险的动作:
movb    $120, 880(%ebp)  -> xu[1000]='x'; 就可能破坏调用者的堆栈,导致程序崩溃
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP