Chinaunix

标题: aix中,变量怎么会这样? [打印本页]

作者: chenzhanyiczy    时间: 2008-05-08 14:22
标题: aix中,变量怎么会这样?
int main()
{
   char b[5];
   strcpy(b,"Hello,Aix");
   printf("b is %s",b);
}

b is Hello,Aix

运行上面竟然不会报错??怎么会这样?难道aix帮这个变量增加了空间?
作者: flw    时间: 2008-05-08 14:25
我再说一遍:
错误的程序未必会得到错误的结果。
作者: chenzhanyiczy    时间: 2008-05-08 14:28
但至少它应该会溢出
作者: chenzhanyiczy    时间: 2008-05-08 14:30
而且每次运行,b 都是等于 Hello,Aix
作者: flw    时间: 2008-05-08 14:39
原帖由 chenzhanyiczy 于 2008-5-8 14:28 发表
但至少它应该会溢出

溢出时又不保证一定不输出 Hello, Aix
作者: cugb_cat    时间: 2008-05-08 14:41
不光是aix中,什么系统中也可能不出错。
作者: chenzhanyiczy    时间: 2008-05-08 14:48
在这种情况,怎样才能发现这个bug?
作者: swordfish.cn    时间: 2008-05-08 14:50
这个要程序员自己检查了。
作者: chenzhanyiczy    时间: 2008-05-08 14:55
假设一个上几万行得程序,虽然有这个bug,但测试时,都是输出正确得结果,那没可能还要一个个去检查吧
作者: flw    时间: 2008-05-08 15:15
原帖由 chenzhanyiczy 于 2008-5-8 14:55 发表
假设一个上几万行得程序,虽然有这个bug,但测试时,都是输出正确得结果,那没可能还要一个个去检查吧

这个问题很好解决。
把 3k 的程序员解雇掉,
换一个 13k 的,就可以了。
作者: chenzhanyiczy    时间: 2008-05-08 15:18
问题是13K的也会犯,即使是低级的错误
作者: flw2    时间: 2008-05-08 15:20
原帖由 chenzhanyiczy 于 2008-5-8 15:18 发表
问题是13K的也会犯,即使是低级的错误


写熟悉了应该就好多了
虽然130的程序员也可能犯低级错误
作者: flw    时间: 2008-05-08 15:21
原帖由 chenzhanyiczy 于 2008-5-8 15:18 发表
问题是13K的也会犯,即使是低级的错误

13k 的也许会犯别的错误,但这个错误一定不会。
作者: chenzhanyiczy    时间: 2008-05-08 15:24
呵呵,flw看来你很自信,这种态度是好的
作者: flw    时间: 2008-05-08 15:27
原帖由 chenzhanyiczy 于 2008-5-8 15:24 发表
呵呵,flw看来你很自信,这种态度是好的

等你明白了什么是当当当当当之后,你会和我一样自信的。
你之所以对我所说的话半信半疑,是因为你不知道这个错误是多么的低级。
作者: chenzhanyiczy    时间: 2008-05-08 15:33
我从来不敢这么自信,即使能达到你这样的水平。没错,这个问题是很低级,但自己也是从这样的错误中锻炼出来的
作者: flw2    时间: 2008-05-08 15:34
原帖由 flw 于 2008-5-8 15:21 发表

13k 的也许会犯别的错误,但这个错误一定不会。


我确实没犯过,偶尔也用strcpy,但是首先是先保证了不会溢出
作者: flw    时间: 2008-05-08 15:39
原帖由 chenzhanyiczy 于 2008-5-8 15:33 发表
没错,这个问题是很低级,但自己也是从这样的错误中锻炼出来的

谁说不是呢?
作者: system888net    时间: 2008-05-08 18:07
原帖由 chenzhanyiczy 于 2008-5-8 14:55 发表
假设一个上几万行得程序,虽然有这个bug,但测试时,都是输出正确得结果,那没可能还要一个个去检查吧


问得好! 顶
这个是软件工程的范畴了.

每个单位写出大些的软件都会有bug, 因此软件的开法实际上是技术+管理,不可偏废....
作者: safedead    时间: 2008-05-08 18:28
标题: AIX还有其它特性
以前在C/C++看过一篇关于字符串常量的老生常谈文字
据说AIX默认允许覆盖字符串常量

比如
char *a = "abcd";
char *b = "efgh";
strcpy(a, b);
是允许的

如果真的是这样
移植起来就会要人命
作者: system888net    时间: 2008-05-08 18:30
原帖由 safedead 于 2008-5-8 18:28 发表
以前在C/C++看过一篇关于字符串常量的老生常谈文字
据说AIX默认允许覆盖字符串常量

比如
char *a = "abcd";
char *b = "efgh";
strcpy(a, b);
是允许的

如果真的是这样
移植起来就会要人命


说得对,是这样的.
作者: system888net    时间: 2008-05-08 18:39
原帖由 safedead 于 2008-5-8 18:28 发表
以前在C/C++看过一篇关于字符串常量的老生常谈文字
据说AIX默认允许覆盖字符串常量

比如
char *a = "abcd";
char *b = "efgh";
strcpy(a, b);
是允许的

如果真的是这样
移植起来就会要人命


说得对,因此对于一个好的程序员来说,编码的良好习惯非常重要.
在strcpy(a,b) 前做一下越界检查,虽然不是高的技巧,但可使移植的代码很快发现一些隐患.
比较有争议的帖子<使C程序比较健壮的良好习惯示例>讲的就是这个思想,当然也不绝对,总之取决与最终的目标!
作者: ivhb    时间: 2008-05-09 10:34
原帖由 safedead 于 2008-5-8 18:28 发表
以前在C/C++看过一篇关于字符串常量的老生常谈文字
据说AIX默认允许覆盖字符串常量

比如
char *a = "abcd";
char *b = "efgh";
strcpy(a, b);
是允许的

如果真的是这样
移植起来就会要人命


编译时候指定 -qro 就可以
作者: marxn    时间: 2008-05-09 20:38
会不会溢出是编译器决定的,跟AIX有什么关系
作者: sanbiangongzi    时间: 2008-05-09 22:19
void foo()
{
   char b[5];
   strcpy(b,"Hello,Aix");
   printf("b is %s",b);
}

int main()
{
   foo();
   return 0;
}

这样试一下,
字符串应该就会覆盖到返回低地址了

[ 本帖最后由 sanbiangongzi 于 2008-5-9 22:25 编辑 ]
作者: sanbiangongzi    时间: 2008-05-09 22:34
上面的错了,理论上会覆盖返回地址,但是gcc的编译器通常会自作多情。比如
#include <stdio.h>

void foo(void)
{
   char b[5];
   
   strcpy(b,"Hello,Aix");
   printf("b is %s",b);
}

int main(int argc, char *argv[])
{
   foo();

   return 0;
}
对应的汇编是:
        .file        "a.c"
        .text
LC0:
        .ascii "Hello,Aix\0"
LC1:
        .ascii "b is %s\0"
.globl _foo
        .def        _foo;        .scl        2;        .type        32;        .endef
_foo:
        pushl        %ebp
        movl        %esp, %ebp
        subl        $24, %esp;b只有5个字节却要分给他24个字节的保留空间;而其当我把5改成25后,这里的24变成了40
        subl        $8, %esp
        pushl        $LC0
        leal        -24(%ebp), %eax
        pushl        %eax
        call        _strcpy
        addl        $16, %esp
        subl        $8, %esp
        leal        -24(%ebp), %eax
        pushl        %eax
        pushl        $LC1
        call        _printf
        addl        $16, %esp
        leave
        ret
        .def        ___main;        .scl        2;        .type        32;        .endef
.globl _main
        .def        _main;        .scl        2;        .type        32;        .endef
_main:
        pushl        %ebp
        movl        %esp, %ebp
        subl        $8, %esp
        andl        $-16, %esp
        movl        $0, %eax
        movl        %eax, -4(%ebp)
        movl        -4(%ebp), %eax
        call        __alloca
        call        ___main
        call        _foo
        movl        $0, %eax
        leave
        ret
        .def        _printf;        .scl        2;        .type        32;        .endef
        .def        _strcpy;        .scl        2;        .type        32;        .endef


因为栈sp指针的东西总是要是4的倍数的,所以我把第12行的$24改成了$8之后,编译这个汇编文件的到的可执行文件输出是:
C:\EP_Backup>a
b is ?@
C:\EP_Backup>

我实在WindowsXP 上用MingW带的gcc编译的
作者: hyyuanqiang    时间: 2008-05-10 20:21
提示: 作者被禁止或删除 内容自动屏蔽
作者: yangdon323    时间: 2008-05-11 19:39
定义字符数组时,我也验证过几种unix系统(包括linux)都会按4的倍数分配空间。
但是写出这样的代码,说明还是新新新手
作者: zx_wing    时间: 2008-05-11 19:56
原帖由 chenzhanyiczy 于 2008-5-8 14:55 发表
假设一个上几万行得程序,虽然有这个bug,但测试时,都是输出正确得结果,那没可能还要一个个去检查吧

我告诉你这种BUG怎么调。
当你的系统出现异常的时候,用调试器从出错的地方一个函数一个函数的往前跟,你会最终会发现在有一点上某个内存地址的值异常了。在这个地址上停一个写断点。重新运行你的程序,当溢出覆盖到这个地址时,写断点就停住了,你就可以找到溢出的地方。
不仅是几万行的程序,上百万行的程序也是这么调的。
作者: MackedNice    时间: 2008-05-11 22:30
原帖由 zx_wing 于 2008-5-11 19:56 发表

我告诉你这种BUG怎么调。
当你的系统出现异常的时候,用调试器从出错的地方一个函数一个函数的往前跟,你会最终会发现在有一点上某个内存地址的值异常了。在这个地址上停一个写断点。重新运行你的程序,当溢 ...

这个方法真是不错。还没有试过这样调试的。以后可以试试!:wink:
作者: zszyj    时间: 2008-05-13 00:16
原帖由 chenzhanyiczy 于 2008-5-8 15:33 发表
我从来不敢这么自信,即使能达到你这样的水平。没错,这个问题是很低级,但自己也是从这样的错误中锻炼出来的

测试时链接efence库, 能保证一旦越界必core dump. 测试完毕后重新链接即可.




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2