strlen参数异常导致越界访问的时候为什么不出错

a_mao 2009-05-11 11:10:49
strlen参数异常导致越界访问的时候为什么不出错
如题
比如
char *p =100 ;
strlen(p) ; 不出错
但访问内容如 if(p[0]==0x12)
就会出错

main()
{
char *p = 100 ;
unsigned long len = 0 ;
len = strlen(p) ; //不出错 为什么
printf("%c" ,p[0]) //出错 ,出错是正常的

}
...全文
1454 72 打赏 收藏 转发到动态 举报
写回复
用AI写文章
72 条回复
切换为时间正序
请发表友善的回复…
发表回复
komai908 2009-05-29
  • 打赏
  • 举报
回复
xempo 2009-05-29
  • 打赏
  • 举报
回复
我的不报错。因为我的(机器)内存102处(字节)的值是0。
lpf000 2009-05-29
  • 打赏
  • 举报
回复
strlen是只做 =='\0'的比较 无须管其值是什么类型
sunzerui 2009-05-29
  • 打赏
  • 举报
回复
学习啦!
volant_hoo 2009-05-15
  • 打赏
  • 举报
回复
路过,随便说说:
strlen和后面的printf差不多,都是只读的访问,按说应该是"要错都错,要不错就都不错",跟操作系统之类的关系应该不大.
出现这种情况,可能和楼主的环境有关系.简单的分析一下可能性:
1. strlen函数被覆盖,这种可能性比较小;
2. 编译的时候进行了优化,可以看到"unsigned long len = 0 ; len = strlen(p) ; //不出错 为什么",这两行代码没有别的交互,有可能被优化掉;
3. strlen参数为const,而printf为一般的类型,不知道这个在楼主的环境中编译后有什么差别.
上述主要还是基于推测,具体的还得楼主弄个汇编出来让大家看看,或者干脆把编译后的程序放出来.
ForestDB 2009-05-15
  • 打赏
  • 举报
回复

$ cat u.c
#include <stdio.h>
#include <string.h>

int main()
{
char * p = 100;
unsigned long len = 0;

printf("1\n"); // 加上这样的语句,知道哪里出错了。
len = strlen(p);

printf("2\n");
printf("%c\n", p[0]);

return 0;
}

$ ./u
1
Segmentation fault

结论:
不见棺材不流泪,不见0x0不回头,还是这句话,这就是strlen的实现原理。
这里是另外一个问题,就是操作系统不会给所有的地址都做映射,比如这里的100
datacode 2009-05-15
  • 打赏
  • 举报
回复
[Quote=引用 62 楼 hurricane880 的回复:]
刚才看了下strlen的源代码
C/C++ code
size_t __cdecl strlen (
const char * str
)
{
const char *eos = str;

while( *eos++ ) ;

return( (int)(eos - str - 1) );
}


确实是访问了地址
[/Quote]

基本所有的库都是这么实现的,说不错的的人眼睛增大点儿,看清楚了...
特别是楼主...
hurricane880 2009-05-15
  • 打赏
  • 举报
回复
char *p=100;这句有意义的
但是应该把100进行类型转换。
hurricane880 2009-05-15
  • 打赏
  • 举报
回复
对于strlen(p);这句根本不生成中间代码,所以不报错
hurricane880 2009-05-14
  • 打赏
  • 举报
回复
刚才看了下strlen的源代码

size_t __cdecl strlen (
const char * str
)
{
const char *eos = str;

while( *eos++ ) ;

return( (int)(eos - str - 1) );
}

确实是访问了地址
hurricane880 2009-05-14
  • 打赏
  • 举报
回复
另外你能解释一下你说的
strlen访问非法地址不出错的确切意思么?访问一个地址就是要“进去”也就是说要读
而strlen根本不做这个事情
之所以strlen“访问”了地址是因为它在等号的右边。
hurricane880 2009-05-14
  • 打赏
  • 举报
回复
你所说的出错是什么概念?

是编译是出错还算运行时出错?,这个代码我使用gcc4.3.3-2运行是有warning的,当然,一个好的编译器是应该通知程序员这样写是有可能有问题的,但是决定权还是程序员的。由于C语言在设计的时候就假设,程序员做的都是对的(这也就是为什么C这么灵活)所以你仍然可以运行这段程序,对于有些系统,如有名的垃圾ms-dos。一个小小的错误可能导致系统崩溃。而对于linux2.6,当然是段错误了,不能访问这个地址的。

关于这个程序:
编译时是否给出警告看编译器
运行时是肯定出错的,经典的段错误
你可以把len=strlen(p);改成strlen(p);这样运行是就不会提示段错误。
原因很简单,编译生成的代码对等号左右两边的处理是不一样的
对于左边只取地址,右边会访问地址。所以运行时就会出现段错误。

当linux完成最初的引导任务后,就会切换到保护模式下,在这种模式下,通过分段和分页机制,(当然了,linux的分段可以无视),由内核来完成对物理地址的访问。把内存访问这样一件极其敏感的事情交给用户来做是很危险的。
如果用户访问了一个非法的地址,内核就会发现,并拒绝用户请求,这是你在屏幕上就会看到段错误这样的提示了。
rwjlqn 2009-05-14
  • 打赏
  • 举报
回复
char *p =100 ;

有意义吗?
ForestDB 2009-05-13
  • 打赏
  • 举报
回复
不见棺材不流泪,不见0x0不回头。
hurricane880 2009-05-13
  • 打赏
  • 举报
回复
1.和OS相关是说内存保护技术,相关内容请去阅读操作系统原理内存管理一章
2.我不懂你说的越界是什么意思,很多术语中文一翻译就变味了。我对越界的理解就是访问了其他程序的地址空间。这个当然有关系,当然也是和OS有关系这个程序拿到DOS早期版本正常运行,但是拿到目前大部分操作系统上一定会出现“。。。。。。”指令引用的"......"内存不能为“read"之类的话,但是对于有的操作系统,可以read,但是不能write,那么就不会报错了
3.环境相关就是看编译是否出错。大部分编译器我想应该会有warning吧,我用vc6.0是编译时有warning的,但是连接就没问题,运行时就看操作系统了。

要想得到确切答案,看内存管理。随便一本操作原理的书都有讲。另外看看c陷阱与缺陷中关于段错误的描述,关于段错误的详细内容在c专家编程里说的比较详细。
[Quote=引用 45 楼 a_mao 的回复:]


1 。如果和os相关,那么说出相关的原因
2. 如果和越界没有关系,那么也说原因
3.环境相关说明环境原因
另外不要动不动说什么不懂,呵呵,这个问题我觉得你要是真能完全说明白了你的水平也很高了
要根据现象找到深层的理论原因
[/Quote]
a_mao 2009-05-13
  • 打赏
  • 举报
回复
57楼说的很对 ,内存管理我了解一些
内核态分段实际什么都没有做,最后的结果是将物理地址映射成了线性地址
应用层的话,采用的是虚地址,10 10 12 的查找,
所以我的判断是,直到地址超出了 cs 段的范围才会出错,
不过似乎可以猜想下,如果我一开始就将p赋值成内核空间的地址比如ffffffff,是否应该马上出错呵呵,等会试验下

存在的问题目前是 :
strlen是否并不访问该地址,
如果strlen访问该地址的话,那么为什么我不能打印出该地址的内容
也就是说

len = strlen(p) ;
printf("%c" ,p[0])
这2行都访问了p的地址 ,按说都应该出错,但实际上如果只算长度就不出错,我的环境是linux2.6 gcc
没有道理strlen访问非法地址不出错但printf就出错,难道printf设计到了内核空间和用户空间的拷贝?

datacodebugs 2009-05-12
  • 打赏
  • 举报
回复
看了要脑残啊...
不看了...
a_mao 2009-05-12
  • 打赏
  • 举报
回复
我想,凡事都要深究,也许只是简单的表面现象,其实也是有很深的内涵的,
我们工程技术人员需要严谨的对待问题的态度,简单的下结论对人对己都是不负责任的
a_mao 2009-05-12
  • 打赏
  • 举报
回复


1 。如果和os相关,那么说出相关的原因
2. 如果和越界没有关系,那么也说原因
3.环境相关说明环境原因
另外不要动不动说什么不懂,呵呵,这个问题我觉得你要是真能完全说明白了你的水平也很高了
要根据现象找到深层的理论原因


向良玉 2009-05-12
  • 打赏
  • 举报
回复
学习
加载更多回复(52)
软件编程规范培训实例与练习 软件编程规范培训实例与练习  问题分类 1 逻辑类问题(A类)-指设计、编码中出现的计算正确性和一致性、程序逻辑控制等方面出现的问题,在系统中起关键作用,将导致软件死机、功能正常实现等严重问题; 接口类问题(B类)-指设计、编码中出现的函数和环境、其他函数、全局/局部变量或数据变量之间的数据/控制传输不匹配的问题,在系统中起重要作用,将导致模块间配合失效等严重问题; 维护类问题(C类)-指设计、编码中出现的对软件系统的维护方便程度造成影响的问题,在系统中不起关键作用,但对系统后期维护造成不便或导致维护费用上升; 可测试性问题(D类)-指设计、编码中因考虑不周而导致后期系统可测试性差的问题。  处罚办法 问题发生率: P=D/S D=DA+0.5DB+0.25DC 其中: P -问题发生率 D -1个季度内错误总数 DA -1个季度内A类错误总数 DB -1个季度内B类错误总数 DC -1个季度内C类错误总数 S -1个季度内收到问题报告单总数 1)当D≥3时,如果P≥3%,将进行警告处理,并予以公告; 2)当D≥5时,如果P≥5%,将进行罚款处理,并予以公告。 目 录 一、逻辑类代码问题 第5页 1、变量/指针在使用前就必须初始化 第5页 【案例1.1.1】 第5页 2、防止指针/数组操作越界 第5页 【案例1.2.1】 第5页 【案例1.2.2】 第6页 【案例1.2.3】 第7页 【案例1.2.4】 第8页 3、避免指针的非法引用 第9页 【案例1.3.1】 第9页 4、变量类型定义错误 第10页 【案例1.4.1】 第10页 5、正确使用逻辑与&&、屏蔽&操作符 第17页 【案例1.5.1】 第17页 6、注意数据类型的匹配 第18页 【案例1.6.1】 第18页 【案例1.6.2】 第18页 7、用于控制条件转移的表达式及取值范围是否书写正确 第20页 【案例1.7.1】 第20页 【案例1.7.2】 第21页 【案例1.7.3】 第22页 8、条件分支处理是否有遗漏 第24页 【案例1.8.1】 第24页 9、引用已释放的资源 第26页 【案例1.9.1】 第26页 10、分配资源是否已正确释放 第28页 【案例1.10.1】 第28页 【案例1.10.2】 第29页 【案例1.10.3】 第30页 【案例1.10.4】 第32页 【案例1.10.5】 第33页 【案例1.10.6】 第35页 【案例1.10.7】 第38页 11、防止资源的重复释放 第39页 【案例1.11.1】 第39页 12、公共资源的互斥性和竞用性 第40页 【案例1.12.1】 第40页 【案例1.12.2】 第40页 二、接口类代码问题 第43页 1、对函数参数进行有效性检查 第43页 【案例2.1.1】 第43页 【案例2.1.2】 第43页 【案例2.1.3】 第44页 【案例2.1.4】 第46页 【案例2.1.5】 第47页 【案例2.1.6】 第48页 2、注意多出口函数的处理 第49页 【案例2.2.1】 第49页 三、维护类代码问题 第51页 1、 统一枚举类型的使用 第51页 【案例3.1.1】 第51页 2、 注释量至少占代码总量的20% 第51页 【案例3.2.1】对XXX产品BAM某版本部分代码注释量的统计 第51页 四、产品兼容性问题 第52页 1、系统配置、命令方式 第52页 【案例4.1.1】 第52页 【案例4.1.2】 第53页 2、设备对接 第54页 【案例4.2.1】 第54页 3、其他 第55页 【案例4.3.1】 第55页 五、版本控制问题 第58页 1、新老代码中同一全局变量不一致 第58页 【案例5.1.1】 第58页 六、可测试性代码问题 第59页 1、调试信息/打印信息的正确性 第59页 【案例6.1.1】 第59页 一、逻辑类代码问题 1、变量/指针在使用前就必须初始化 【案例1.1.1】 C语言中最大的特色就是指针。指针的使用具有很强的技巧性和灵活性,但同时也带来了很大的危险性。在XXX的代码中有如下一端对指针的灵活使用: ... ... _UC *puc_card_config_tab; ... ... Get_Config_Table(

69,381

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧