证明 "int *p = malloc(1); p[0]" 是未定义的行为
Proving that "int *p = malloc(1); p[0]" is undefined behavior
我试图说服(引用 C99 标准的特定部分)一位同事以下是未定义的行为:
int *p = malloc(1);
p[0] = 0;
但是我在标准中找不到明确确保这是未定义的具体部分。 我正在专门寻找标准中从这些行得出结论的逻辑步骤:未定义的行为。第一行是void *
到int *
的转换吗?第二行的赋值?
我能找到的关于 malloc
的唯一相关部分是 returns 一个适当对齐的指针 (7.20.3):
The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object or an array of such objects in the space allocated (...)
我试着在正常情况下搜索 space,但是由于 white space[=28=,噪音太大了] 和其他词汇问题。
int *p = malloc(1);
p[0] = 0;
这是未定义的行为,因为您已经分配了 1 个字节,而在上面的分配中您试图写入四个字节(假设 int
是四个字节)。只要 sizeof(int) > 1
.
就成立
malloc(1)
returns 1 字节大缓冲区的地址。
一个int
一般来说大于1个字节
因此,将一个 int 值赋给一个 1 字节的大缓冲区是 UB。
malloc
返回的指针不需要在 c 中转换,因为它们在使用时会安全自动地提升为正确的指针类型。
从 7.20.3.3 添加 malloc 函数 到您的引用:
The malloc function allocates space for an object whose size is
specified by size and whose value is indeterminate.
The malloc function returns either a null pointer or a pointer to the allocated space.
所以有两种可能的未定义行为来源,一种是覆盖(int 的大小保证为 16 位或更多,但您只分配 1 个字节,在几乎所有系统上都是 8 位)缓冲区,其次是可能取消引用空指针。
从6.5.2.1数组下标开始,p[0] = 0
相当于*p = 0
。 *p
的类型是 int
,因此它会用 0
填充 sizeof(*p) * CHAR_BIT
位,这可能并不都属于导致 UB 的已分配缓冲区。
第一行代码(赋值)中没有未定义的行为,UB 如果有则在第二行(取消引用)。
但是在 CHAR_BIT
很大并且 sizeof(int)
是 1
的机器上,对于 malloc
不是 [=20] 的情况,这将是明确定义的行为=] 一个空指针。
6.5.3.2 Address and indirection operators
...
Semantics
The unary & operator yields the address of its operand. If the operand
has type ‘‘type’’, the result has type ‘‘pointer to type’’. If the
operand is the result of a unary * operator, neither that operator nor
the & operator is evaluated and the result is as if both were omitted,
except that the constraints on the operators still apply and the
result is not an lvalue. Similarly, if the operand is the result of
a [] operator, neither the & operator nor the unary * that is
implied by the [] is evaluated and the result is as if the &
operator were removed and the [] operator were changed to a +
operator. Otherwise, the result is a pointer to the object or function
designated by its operand.
The unary * operator denotes indirection. If the operand points to a
function, the result is a function designator; if it points to an
object, the result is an lvalue designating the object. If the operand
has type ‘‘pointer to type’’, the result has type ‘‘type’’. If an
invalid value has been assigned to the pointer, the behavior of the
unary * operator is undefined.
[]
运算符是指针上隐含的 *
运算符。分配给指针的值是 无效 对于 int
只要 sizeof( int ) > 1
.
行为未定义。
而NULL
是一个无效的指针,所以这也涵盖了malloc()
返回NULL
。
标准引述:
J.2, Undefined behavior: The behavior is undefined in the following circumstances: ... An array subscript is out of range, even if an object is apparently accessible with the given subscript
6.2.5, Types, 20: An array type describes a contiguously allocated nonempty set of objects.
只要 sizeof(int) > 1
,您的 malloc(1)
没有分配一组非空对象,因此分配的数组大小为零,并且使用 p[0]
您可以使用下标访问超出范围。 QED.
代码 *p
涵盖于(至少 - 其他部分也可能涵盖)6.3.2.1/1:
An lvalue is an expression (with an object type other than void) that potentially
designates an object; if an lvalue does not designate an object when it is evaluated, the behavior is undefined.
"object"的定义是:
region of data storage in the execution environment, the contents of which can represent values
左值 *p
指定 space 的 sizeof(int)
字节,但是只有 1
字节的存储可以表示值(换句话说,未分配的 space 不能构成对象的一部分)。因此,如果 sizeof(int) > 1
,则 *p
不指定对象。
对于问题 p[0]
中的实际代码:这相当于 *(p+0)
。从 6.5.6/8 开始,我不清楚 p + 0
是否会导致 UB。但这是没有实际意义的,因为即使它不会导致 UB,推迟结果也会如上所示;所以 p[0]
无论哪种方式都会导致 UB。
我试图说服(引用 C99 标准的特定部分)一位同事以下是未定义的行为:
int *p = malloc(1);
p[0] = 0;
但是我在标准中找不到明确确保这是未定义的具体部分。 我正在专门寻找标准中从这些行得出结论的逻辑步骤:未定义的行为。第一行是void *
到int *
的转换吗?第二行的赋值?
我能找到的关于 malloc
的唯一相关部分是 returns 一个适当对齐的指针 (7.20.3):
The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object or an array of such objects in the space allocated (...)
我试着在正常情况下搜索 space,但是由于 white space[=28=,噪音太大了] 和其他词汇问题。
int *p = malloc(1);
p[0] = 0;
这是未定义的行为,因为您已经分配了 1 个字节,而在上面的分配中您试图写入四个字节(假设 int
是四个字节)。只要 sizeof(int) > 1
.
malloc(1)
returns 1 字节大缓冲区的地址。
一个int
一般来说大于1个字节
因此,将一个 int 值赋给一个 1 字节的大缓冲区是 UB。
malloc
返回的指针不需要在 c 中转换,因为它们在使用时会安全自动地提升为正确的指针类型。
从 7.20.3.3 添加 malloc 函数 到您的引用:
The malloc function allocates space for an object whose size is specified by size and whose value is indeterminate.
The malloc function returns either a null pointer or a pointer to the allocated space.
所以有两种可能的未定义行为来源,一种是覆盖(int 的大小保证为 16 位或更多,但您只分配 1 个字节,在几乎所有系统上都是 8 位)缓冲区,其次是可能取消引用空指针。
从6.5.2.1数组下标开始,p[0] = 0
相当于*p = 0
。 *p
的类型是 int
,因此它会用 0
填充 sizeof(*p) * CHAR_BIT
位,这可能并不都属于导致 UB 的已分配缓冲区。
第一行代码(赋值)中没有未定义的行为,UB 如果有则在第二行(取消引用)。
但是在 CHAR_BIT
很大并且 sizeof(int)
是 1
的机器上,对于 malloc
不是 [=20] 的情况,这将是明确定义的行为=] 一个空指针。
6.5.3.2 Address and indirection operators
...
Semantics
The unary & operator yields the address of its operand. If the operand has type ‘‘type’’, the result has type ‘‘pointer to type’’. If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue. Similarly, if the operand is the result of a [] operator, neither the & operator nor the unary * that is implied by the [] is evaluated and the result is as if the & operator were removed and the [] operator were changed to a + operator. Otherwise, the result is a pointer to the object or function designated by its operand.
The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object. If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’. If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.
[]
运算符是指针上隐含的 *
运算符。分配给指针的值是 无效 对于 int
只要 sizeof( int ) > 1
.
行为未定义。
而NULL
是一个无效的指针,所以这也涵盖了malloc()
返回NULL
。
标准引述:
J.2, Undefined behavior: The behavior is undefined in the following circumstances: ... An array subscript is out of range, even if an object is apparently accessible with the given subscript
6.2.5, Types, 20: An array type describes a contiguously allocated nonempty set of objects.
只要 sizeof(int) > 1
,您的 malloc(1)
没有分配一组非空对象,因此分配的数组大小为零,并且使用 p[0]
您可以使用下标访问超出范围。 QED.
代码 *p
涵盖于(至少 - 其他部分也可能涵盖)6.3.2.1/1:
An lvalue is an expression (with an object type other than void) that potentially designates an object; if an lvalue does not designate an object when it is evaluated, the behavior is undefined.
"object"的定义是:
region of data storage in the execution environment, the contents of which can represent values
左值 *p
指定 space 的 sizeof(int)
字节,但是只有 1
字节的存储可以表示值(换句话说,未分配的 space 不能构成对象的一部分)。因此,如果 sizeof(int) > 1
,则 *p
不指定对象。
对于问题 p[0]
中的实际代码:这相当于 *(p+0)
。从 6.5.6/8 开始,我不清楚 p + 0
是否会导致 UB。但这是没有实际意义的,因为即使它不会导致 UB,推迟结果也会如上所示;所以 p[0]
无论哪种方式都会导致 UB。