证明"int*p = malloc(1); p [0]"是未定义的行为

ano*_*nol 15 c malloc language-lawyer

我试图说服(引用C99标准的具体部分)一位同事,以下是未定义的行为:

int *p = malloc(1);
p[0] = 0;
Run Code Online (Sandbox Code Playgroud)

但我无法在标准中找到明确确保未定义的具体部分.我正在寻找标准中从这些线到结论的逻辑步骤:未定义的行为.它是从第一行转换void *int *第一行吗?第二行的作业?

我能找到的唯一相关部分malloc是它返回一个适当对齐的指针(7.20.3):

如果分配成功,则返回指针,以便将其分配给指向任何类型对象的指针,然后用于在分配的空间中访问此类对象或此类对象的数组(...)

我试着在标准中寻找空间,但是由于空白和其他词汇问题,噪音太大了.

Moh*_*ain 18

7.20.3.3添加malloc函数到你的引用:

malloc函数为一个对象分配空间,该对象的大小由size指定,其值是不确定的.
malloc函数返回空指针或指向已分配空间的指针.

所以有两种可能的未定义行为来源,一种是覆盖(int的大小保证是16位或更多,但是你只分配1个字节,几乎所有系统都是8位)缓冲区,第二种可能是de - 引用空指针.

6.5.2.1数组下标,p[0] = 0相当于*p = 0.类型*p是一个int所以它将填充sizeof(*p) * CHAR_BIT0,可能不是所有都属于分配的缓冲区导致UB.

在第一行代码(赋值)中没有未定义的行为,如果任何行将在第二行(取消引用),则UB.

但是,在一些机器上CHAR_BIT是大sizeof(int)1,这将是良好定义的行为时,情况malloc并没有return一个空指针.

  • @Vincent:请发布标准要求`sizeof(int)> = 2`的段落.唯一的要求是`sizeof(char)== 1`.并且PeterCordes没有声明"一个`int`必须有16位".他刚刚声明它至少有**16位,这是从"int"(+/- 32767)所需的最小范围开始的.`sizeof(int)`的结果来自于此和`CHAR_BIT`.(但他混淆了大小和宽度) (10认同)
  • `int`大小的唯一保证是它至少是16位,对吧?`CHAR_BIT`是否可能是16,而`sizeof(int)== sizeof(char)`?该代码在该奇怪的C实现上是合法的.re:@Oliver的观点:在标准的某个地方,在对象之外写作是UB.不过,我自己没有快速拨号的标准来引用它的片段. (6认同)
  • @PeterCordes是的你是对的.有一些机器(Crays),其中CHAR_BIT是32.这意味着sizeof(int)= sizeof(char)= 1.这意味着`malloc(1)`相当于`malloc(sizeof(int))`但是在ILP32和LP64上系统这显然是UB. (6认同)
  • @Peter Cordes实际上没有任何类似"标准中的int必须有16位".除char之外,所有类型的大小要求仅以char的大小为单位给出.该标准保证sizeof(int)> = 2. (2认同)
  • @Vincent根据`C`规范,`int`必须支持至少`[-32767,+ 32767]`范围,该范围映射到最小16位要求.并且`sizeof(int)`是`NUMBER_OF_BITS/CHAR_BIT` (2认同)

gio*_*gim 7

int *p = malloc(1);
p[0] = 0;
Run Code Online (Sandbox Code Playgroud)

这是未定义的行为,因为您已经分配了1个字节,并且在上面的赋值中,您尝试写入4个字节(假设int是4个字节).这只适用于sizeof(int) > 1.


And*_*nle 5

6.5.3.2地址和间接运营商

...

语义

一元&运算符产生其操作数的地址.如果操作数具有类型''type'',则结果具有类型''指向类型''的指针.如果操作数是一元*运算符的结果,则不会对该运算符和&运算符进行求值,结果就好像两者都被省略,除了对运算符的约束仍然适用且结果不是左值.类似地,如果操作数是[]运算符的结果,则[]运算符和[]暗示的一元*都不会被计算,结果就像删除了&运算符并且[]运算符被更改为a +运算符.否则,结果是指向由其操作数指定的对象或函数的指针.

一元*运算符表示间接.如果操作数指向函数,则结果是函数指示符; 如果它指向一个对象,则结果是指定该对象的左值.如果操作数的类型为''指向类型'',则结果的类型为''type''.如果为指针分配了无效值,则unary*运算符的行为未定义.

[]运营商是一个隐含*的指针操作.分配给该指针的值是无效的用于int只要sizeof( int ) > 1.

行为未定义.

并且NULL是一个无效的指针,所以这也包括malloc()返回NULL.


Pau*_*vie 5

标准引用:

J.2,未定义的行为:在以下情况下,行为未定义:...数组下标超出范围,即使某个对象显然可以使用给定的下标访问

6.2.5,类型,20:数组类型描述了连续分配的非空对象集.

只要sizeof(int) > 1malloc(1)没有分配一组非空对象,那么分配的数组大小为零,并且p[0]您使用超出范围的下标进行访问.QED.