gcc 出bug了

软件和网站开发以及相关技术探讨
回复
zdfzr
帖子: 23
注册时间: 2011-09-18 18:42
系统: Debian GNU/Linux

gcc 出bug了

#1

帖子 zdfzr » 2013-11-28 18:43

先看下代码有没有问题。

代码: 全选

1.c
unsigned char verify(unsigned char data[], unsigned char length)
{
	unsigned char result = 0;
	for (int i = 0; i < length; i++) {
		result += data[i];
	}
	result += 0x5a;
	return result;
}

代码: 全选

2.c
#include <stdio.h>
//unsigned char verify(unsigned char data[], unsigned char length);
int main()
{
	unsigned int a;
	unsigned char b[5] = {0x35, 0x5b, 0x5c, 0x5d, 0x5e};
	a = verify(b, 5);
	printf("%d\n", a);
	return 0;
}
我先将1.c编译为动态库:gcc -Wall 1.c -o liba.so -shared -std=gnu99 -O3
再将2.c编译链接liba.so,verify函数返回的应当是0-255的数,但是返回的是257,最后打印出来的是257。
如果将1.c编译时去除优化:gcc -Wall 1.c -o liba.so -shared -std=gnu99 -O0
再用2.c编译的程序执行就正确了,返回1。
如果1.c仍然用-O3编译,在2.c中声明语句前的注释去掉,编译的结果却是正确的,返回1。
在gcc4.7.2和4.8.1中都有这个错误,不知是不是我的代码有什么问题么。(我是在用Python调用动态库的时候发现这个问题的)
头像
huangbster
帖子: 187
注册时间: 2012-10-29 11:35
系统: UBUNTU

Re: gcc 出bug了

#2

帖子 huangbster » 2013-11-28 20:31

这恐怕不是GCC的BUG,你把1.c中的unsigned char length改为int length,试试。
zdfzr
帖子: 23
注册时间: 2011-09-18 18:42
系统: Debian GNU/Linux

Re: gcc 出bug了

#3

帖子 zdfzr » 2013-11-28 20:44

将1.c中的unsigned char length改为int length,还是不行,执行程序仍然输出是257。
从结果看,这个主要取决于编译时的优化选项,-O0时就能得到正确的结果,-O1时就已经变成上面的错误的结果了。
头像
huangbster
帖子: 187
注册时间: 2012-10-29 11:35
系统: UBUNTU

Re: gcc 出bug了

#4

帖子 huangbster » 2013-11-28 22:01

不是GCC的BUG,改为这个int verify(unsigned char data[], int length)就可以了。
zdfzr
帖子: 23
注册时间: 2011-09-18 18:42
系统: Debian GNU/Linux

Re: gcc 出bug了

#5

帖子 zdfzr » 2013-11-28 22:15

不是GCC的BUG,改为这个int verify(unsigned char data[], int length)就可以了。
这样做就和最初的意义不同了,我想做的是对一个字符数组进行累加校验,只取校验和的最后一个字节,(单独加的0x5a是做一个偏置),要返回一个字节的数据作为校验结果,如果返回int型,在调用函数中还需要做相关的处理。
而且我明明返回的result是一个unsigned char型的数据,不可能超过255,但是结果就有问题。
在未优化的时候,就可以输出正确的结果,优化后就出现问题,感觉是gcc在优化过程中做了不该做的事,我不懂x86汇编,所以也看不出它怎么优化的代码。
头像
huangbster
帖子: 187
注册时间: 2012-10-29 11:35
系统: UBUNTU

Re: gcc 出bug了

#6

帖子 huangbster » 2013-11-28 22:20

你可以看到warning: implicit declaration of function ‘verify’ [-Wimplicit-function-declaration]
如果出现这种提示,那么GCC会把返回值默认为int。
zdfzr
帖子: 23
注册时间: 2011-09-18 18:42
系统: Debian GNU/Linux

Re: gcc 出bug了

#7

帖子 zdfzr » 2013-11-29 18:24

我知道你的意思了,在一般的程序中都会带有声明,不会发生这种问题。
但是我还是有些困惑,unsigned char的数据在最后返回时会超过255,感觉是在最后一步加法的时候,gcc没有把数据截断,而直接返回了。
现在主要是我要在Python中调用这个函数,它返回一个大于255的数,我只能在Python中再做处理才能用。
还有你说的返回值默认为int型,这应该不对,因为在-O0的时候结果是正确的,它返回的确实是unsigned char,但是在-O1,-O2,-O3的时候返回就不对了,感觉太奇怪了。
头像
huangbster
帖子: 187
注册时间: 2012-10-29 11:35
系统: UBUNTU

Re: gcc 出bug了

#8

帖子 huangbster » 2013-11-29 20:22

你得到的数值257实际上是0x0101,如果你把unsigned int a;定义为unsigned char a;那么你同样可以得到一个正确的结果。
你说没有优化时可以得到正确的,那是因为恰好高8位的数值为0。
这就是为什么有些程序优化后就不正确,那是因为程序没有写好。C语音就是这样的,陷阱很多。
zdfzr
帖子: 23
注册时间: 2011-09-18 18:42
系统: Debian GNU/Linux

Re: gcc 出bug了

#9

帖子 zdfzr » 2013-11-29 22:06

我又用clang3.0试了一下,编译用:clang -Weverything -c 1.c -std=c99 -O3
再运行ld 1.o -shared -o lib1.so
2.c仍然用最初的gcc编译,这时候调用就是正确的结果,输出是1,改变clang的优化选项不影响输出的结果,可见应当是gcc的优化不当导致的结果错误。
再用回gcc编译的lib1.so,结果又变为257。
头像
huangbster
帖子: 187
注册时间: 2012-10-29 11:35
系统: UBUNTU

Re: gcc 出bug了

#10

帖子 huangbster » 2013-11-30 9:11

我已经说了,GCC并没有出错,你把unsigned int a;定义为unsigned char a试试,肯定得到正确答案。
这里的问题是GCC需不需要把0x00000101转化为0x00000001的问题。我的意见是,既然是优化,那么这个转化的动作是多余的,没有任何意义;要不就干脆不要优化算了。
zdfzr
帖子: 23
注册时间: 2011-09-18 18:42
系统: Debian GNU/Linux

Re: gcc 出bug了

#11

帖子 zdfzr » 2013-11-30 18:16

好吧,在源文件中声明函数后优化编译的确不会出错。
就是还有最后一个问题:在Python中动态调用c的函数是不是要有什么规范?我这里调用优化后的动态库,返回就是上面的错误结果。
在Python中是要做什么处理么?
头像
huangbster
帖子: 187
注册时间: 2012-10-29 11:35
系统: UBUNTU

Re: gcc 出bug了

#12

帖子 huangbster » 2013-12-01 10:15

import dl
h=dl.open('liba.so');
b=bytes(b'\x35\x5b\x5c\x5d\x5e')
a=h.call('verify',b,5)&0xff
print a
zdfzr
帖子: 23
注册时间: 2011-09-18 18:42
系统: Debian GNU/Linux

Re: gcc 出bug了

#13

帖子 zdfzr » 2013-12-01 11:57

感谢解答。我已经搞清楚这个问题了。
回复