投掷空*指针不安全吗?

  • 本文关键字:不安全 指针 c
  • 更新时间 :
  • 英文 :


例如在下面的代码中:

#include <stdio.h>
int main()
{
char i = 0;
char j = 0;
char *p = &i;
void *q = p;
int *pp = q;
printf("%d %dn", i, j);
*pp = -1;
printf("%d %dn", i, j);
return 0;
}

如果我使用 gcc 版本 8.1.0x64(Ubuntu 8.1.0-5ubuntu1~16.04(编译,输出是:
0 0-1
-1
现在,我使用 cast 到 int *

#include <stdio.h>
int main()
{
char i = 0;
char j = 0;
char *p = &i;
void *q = p;
int *pp = (int *)q;
printf("%d %dn", i, j);
*pp = -1;
printf("%d %dn", i, j);
return 0;
}

结果与上一个相同。
使用 clang-6.0 x64 时,输出为:0

0-1 0
代码显然是缓冲区溢出吗?
我希望我已经解释清楚了。

你实际上有两个问题:

首先是你打破了严格的别名并具有未定义的行为

第二个问题是,在大多数现代平台上,int的大小为四个字节,指针pp仅指向单个字节。因此,您向*pp所做的赋值将超出界限,导致未定义的行为。

强制转换或不强制转换,您本质上是尝试使用不兼容的类型,导致违反严格的别名规则。

根据C11第6.5章,

对象的存储值只能由具有以下 以下类型:88(

— 与对象的有效类型兼容的类型,

— 与对象的有效类型兼容的类型的限定版本,

— 一种类型,它是与 的有效类型对应的有符号或无符号类型 对象

— 一种类型,它是与 的限定版本相对应的有符号或无符号类型 对象的有效类型,

— 包含上述类型之一的聚合或联合类型 成员(递归地包括子聚合或包含的联合的成员(,或

— 字符类型。

但是,您尝试通过int类型访问为char分配的内存。这违反了严格的别名。

也就是说,该标准保证char的大小为 1 字节,int的大小为>=char。因此,访问将超出界限并导致未定义的行为。

最新更新