c语言作为最基础的语言,经历了这么多年的迭代,它的标准里依然存在很多未定义的东西,而不同的编译器就会出现不一样的结果,这边blog主要是总结一些可能出现的和编译器的编译结果有关的漏洞

有符号和bit字段的比较

c语言有种结构体, 用的是bit位:

1
2
3
4
5
struct a {
unsigned f1 : 8;
unsigned f2 : 2;
unsigned f3 : 6;
} t1;

这个结构体最终的sizeof(t1)为2, 因为它只用了2个字节存储数据.

然而, 当一个int类型的结构体和t1的字段比较时, 结果就未知了.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

void main(void) {
struct a {
unsigned f1 : 8;
unsigned f2 : 2;
unsigned f3 : 6;
} t1;
int t2 = 0xffffffff;

t1.f1 = 0xaa;
printf("%d\n", t2 > t1.f1);
}

上面的代码, gcc的结果就是0, 而使用visual studio编译的就是1.

这种无符号和有符号的比较一般是要将有符号的数变成无符号再比较的, 在汇编层就是ja, jb这种跳转, 然而gcc的就是先把f1扩展成无符号的int, 然后有符号比较. 导致输出就是0. 这样就可能出现安全漏洞.

而且 gcc t.c -Werror -Wall -Wextra -Wconversion这样编译的情况下, 依然不会有任何警告!!

无符号和0的比较

1
2
3
4
5
6
7
8
9
10
11
struct s{
unsigned int len;
char *buffer;
} *a;

int not_safe(struct s *ptr){
if(ptr->len - sizeof(struct s) < 0){
return 0;
}
return 1;
}

gcc默认是不会警告的, 只有启用-Wextra才会警告这种行为, 所以遇到这种比较可以关注一下