c++越界为啥不报错

xxdd 发布于 2015/09/06 12:29
阅读 955
收藏 0
#include <stdio.h>
void fun(int *n)
{
        n[111] = 0;
}

int main()
{
        int *a = new int[2];
        fun(a);
        printf("aaa\n");
        return 0;
}

//这样不报错


#include <stdio.h>
void fun(int *n)
{
        n[111] = 0;
}

int main()
{
        int a[2];
        fun(a);
        printf("aaa\n");
        return 0;
}
//这样也不报错,

为什么?linux环境,g++编译器。

运行结果

[root@f2 ~]# ./a.out
aaa

[root@f2 ~]# g++ -v
使用内建 specs。
COLLECT_GCC=/usr/bin/g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i686-redhat-linux/4.5.1/lto-wrapper
目标:i686-redhat-linux
配置为:../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,lto --enable-plugin --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i686 --build=i686-redhat-linux
线程模型:posix
gcc 版本 4.5.1 20100924 (Red Hat 4.5.1-4) (GCC)


加载中
1
T
Tudorex
printf("aaa\n"); 这不是在打印a字符吗?, 而且, 只有段越界才会引起进程的段错误信号, 你访问的地址仍然在进程的合法空间范围内, 当然空指针这类地址基本不合法。
T
Tudorex
回复 @xxdd : 看看gdb 进程的info proc mappings 或者去cat /proc/$pid/maps, 崩溃指的是程序read, write, execute了一个virtual address, 这个address不在操作系统给其进程分配的虚拟地址段之内, 称其为段错误
MZHS
MZHS
回复 @xxdd : 我的理解是,只有当指针指向只读区域时,你更改才会报错。想想八门神器,一个程序都可以改别的程序里的内存值,这不就很好的解释了你的疑问了吗?
xxdd
xxdd
您好,我指的是fun()函数里面的n[111] ,已经越界了,为什么程序可以正常运行,而不是崩溃?
1
m
magiclogy

因为根本报不了错。

编译器,编译器怎么判断数组下标的范围?没有任何一种万无一失的方法,最多用静态检查工具,处理掉一些错误。

运行期,程序持有的信息更少,数组元素的访问就是数组其实元素的地址+偏移量计算出地址。这个时候就是对地址的直接访问,运行期是不会记录类型信息的,根本不知道这个数组设定的大小。这个时候程序是否崩溃就要看人品了,只有操作系统发现你访问了不该访问的内存区域,程序才会崩溃。

xxdd
xxdd
谢谢,应该是这样的。
0
harleyliao
harleyliao
c++本来就不会检查边界的,所以遇到数组参数的时候,一般会加一个长度, 而java是基于这个问题做了优化
xxdd
xxdd
编译器不检查,但是为什么运行的时候,也不报错?
0
PYPlus
PYPlus
数组下标越界是undefined behavior.  结果是未定义的 知道什么意思吧
xxdd
xxdd
两种写法程序都可以正常运行,为啥?明明操作了非法的地址。
0
chunquedong
chunquedong
越界是undefined behavior。所谓undefined behavior就是怎样都行,可以崩溃、可以什么都不干。你如果非要问为什么C++这样规定,那是因为检查这些错误代价实在太大了。
xxdd
xxdd
您好,我想知道的是,为什么这个程序可以正常运行?数组已经指向了非法的地址。
0
xpbob
xpbob
数组传递变成指针,他允许你进行修改,改的对不对成了问题
0
范泽
范泽

你把堆改成栈再试试

范泽
范泽
回复 @xxdd : 堆所分配的是系统中剩余的可用内存。new出来的内存指针所指向的地址,在你指定的大小之后,仍然可能有很大一块可用内存,不报错是有可能的。
xxdd
xxdd
int a[2]; fun(a); 这个就是栈吧?
0
c521wy
c521wy
这应该和系统内存分配有关系吧,报错应该是系统认为地址非法给你报错,系统肯定是认为你这个地址不非法呗,所以不报错
0
Force武装卫队
Force武装卫队
new int[2] 是从堆上分配的,数组越界是未定义行为,可能是没有进程默认堆大,没有非法访问,所以没有 coredump 掉 。
Force武装卫队
Force武装卫队
你越界大一些看看
xxdd
xxdd
好像是这个原因,那栈上那个为什么也不报错?
0
hawkyoung
hawkyoung

楼主听说过“缓冲区溢出”的说法吧

我个人理解一个指针本来就能在自己的地盘里指来指去,想要指到哪里是程序员的自由,编译器不做这方面的任何限制与检查。

Linux上检查缓冲区溢出跟内存泄露可以试试valgrind还有电网electric-fence


返回顶部
顶部