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

时间:2015-11-18 09:25:39

标签: c malloc language-lawyer

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

int *p = malloc(1);
p[0] = 0;

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

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

  

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

我尝试在常规中使用 space 进行grepping,但由于空格和其他词汇问题而导致噪音太大。

6 个答案:

答案 0 :(得分:18)

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

  

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

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

6.5.2.1数组下标p[0] = 0相当于*p = 0*p的类型为int,因此它会填充sizeof(*p) * CHAR_BIT0,这些位可能并非都属于分配的缓冲区,从而导致UB。

第一行代码(赋值)中没有未定义的行为,UB(如果有的话)在第二行(取消引用)。

但是在CHAR_BIT较大且sizeof(int)1的计算机上,对于malloc不{{1} {{1}的情况,这将是明确定义的行为空指针。

答案 1 :(得分:7)

int *p = malloc(1);
p[0] = 0;

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

,这就适用

答案 2 :(得分:5)

6.5.3.2 Address and indirection operators

  

...

     

<强>语义

     

一元&amp;运算符产生其操作数的地址。如果是操作数   类型为''type'',结果有''指向类型''的指针。如果   操作数是一元*运算符的结果,既不是运算符也不是运算符   和&amp;运算符被评估,结果就像两个都被省略,   除了对运营商的约束仍然适用和   结果不是左值。同样,如果操作数是结果   a []运算符,&amp;算子也不是一元*   评估[] 隐含的结果,结果就像&amp;   删除了运算符,并将[]运算符更改为+   运营商。否则,结果是指向对象或函数的指针   由其操作数指定。

     

一元*运算符表示间接。如果操作数指向a   功能,结果是功能指示符;如果它指向一个   对象,结果是指定对象的左值。如果是操作数   有类型''指向类型'',结果类型''类型''。 如果是   无效值已分配给指针,行为   unary *运算符未定义。

[]运算符是指针上隐含的*运算符。只要int,分配给指针的值为sizeof( int ) > 1无效

行为未定义。

并且NULL是无效指针,因此这也涵盖malloc()返回NULL

答案 3 :(得分:5)

标准引用:

  

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

     

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

只要sizeof(int) > 1,您的malloc(1)没有分配一组非空对象,所以分配的数组大小为零,并且使用p[0]访问时带有下标范围。 QED。

答案 4 :(得分:2)

代码*p涵盖(至少 - 其他部分也可能涵盖它)6.3.2.1/1:

  

lvalue是一个潜在的表达式(对象类型不是void)   指定一个对象;如果左值在评估时未指定对象,则行为未定义。

“对象”的定义是:

  

执行环境中的数据存储区域,其内容可以表示值

左值*p指定sizeof(int)个字节的空间,但是只有1个字节的存储可以表示值(换句话说,未分配的空间不能构成对象的一部分) 。因此,如果sizeof(int) > 1,则*p不会指定对象。

对于问题p[0]中的实际代码:这相当于*(p+0)。从6.5.6 / 8我不清楚p + 0是否会导致UB。但这没有实际意义,因为即使它不会导致UB,也会如上所示引用结果;所以p[0]会导致UB。

答案 5 :(得分:0)

malloc(1)

将地址返回到1字节的大缓冲区。

一般来说,int大于1个字节。

因此,为1字节大缓冲区分配一个int值是UB。

malloc返回的指针不需要在c中输入,因为它们在使用时可以安全地自动提升为正确的指针类型。