sscanf 导致地址越界

Posted Li-Yongjun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sscanf 导致地址越界相关的知识,希望对你有一定的参考价值。

问题

test.c

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main(int argc, char *argv[])

	int a = 100;
	uint8_t b;

	sscanf("0x15", "0x%x", &b);

	printf("a = 0x%x\\n", a);
	printf("b = 0x%x\\n", b);

	return EXIT_SUCCESS;

$ ./test.out 
a = 0x0
b = 0x15

a 的值为什么变成 0 了呢?

解答

因为 sscanf 在给 b 赋值时,由于指定的参数格式是 %x,所以 sscanf 认为 b 是一个 unsigned int 类型,所以把 &b 转换成了 unsigned int * 类型,这样在给 b 赋值时,就是按照 unsigned int 这么大空间进行赋值,结果就操作了别的变量的内存,导致程序出问题。
下图 a) 是我们期望的样子,可是由于 “%x”,导致 &b “管控”的空间从一个字节扩大到了四个字节,“侵占”了变量 a 的空间,如图 b),导致 a 的值被篡改。

避免

其实在编译时,编译器就已经发出了警告。所以我们在编写代码时,要时刻留意编译器报的警告,能够帮助我们纠正不少失误。
因此,提交代码的一个原则就是:尽量不引入新的警告。

$ gcc test.c -o test.out
test.c: In function ‘main’:
test.c:10:21: warning: format ‘%x’ expects argument of type ‘unsigned int *’, but argument 3 has type ‘uint8_t *’ aka ‘unsigned char *’ [-Wformat=]
   10 |  sscanf("0x15", "0x%x", &b);
      |                    ~^   ~~
      |                     |   |
      |                     |   uint8_t * aka unsigned char *
      |                     unsigned int *
      |                    %hhx

推荐写法

方法一:使用"%hhx"

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main(int argc, char *argv[])

	int a = 100;
	uint8_t b;

	sscanf("0x15", "0x%hhx", &b);

	printf("a = 0x%x\\n", a);
	printf("b = 0x%x\\n", b);

	return EXIT_SUCCESS;

$ ./test.out 
a = 0x64
b = 0x15

方法二:使用 int 类型中间变量进行转储。

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

int main(int argc, char *argv[])

	int a = 100;
	uint8_t b;
    int c;

	sscanf("0x15", "0x%x", &c);
    b = (uint8_t)c;

	printf("a = 0x%x\\n", a);
	printf("b = 0x%x\\n", b);

	return EXIT_SUCCESS;

$ ./test.out 
a = 0x64
b = 0x15

以上是关于sscanf 导致地址越界的主要内容,如果未能解决你的问题,请参考以下文章

内存越界一定会导致程序崩溃吗?详解内存越界

C语言sprintf与sscanf函数[总结]

C语言sprintf与sscanf函数[总结]

C语言sprintf与sscanf函数[总结]

裁剪图像会导致越界错误[关闭]

强制类型转换?