C标准的严格解释允许上可能无效的指针操作(Allowed operations on an poss

2019-10-23 18:02发布

Original Question

(please see "Edit: Updated scenario")

This question might be a duplicate in one or another way to a huge collection of questions around undefined behavior of pointers to objects that gone out of scope etc. But all questions I found here to this topic are mostly specialized use cases. So I would like to spin the question upside down, not asking if something is forbidden, but WHAT exactly is allowed?

To have a possible scenario: You have a function, that takes a pointer - you don't know if it came from a (still) valid object. Which operations are under all circumstances NOT undefined behavior? Which might have unspecified side conditions?

int * myFunc(const int * const A, int * B)
{
   ...
}

Edit: Updated Secenario

In the comments to the question and Matt McNabbs answer it was pointed out that UB has risen most likely anyway, as an invalid pointer(s value) is used during call the function in the scenario. Therefore I will change the scenario a little (following the example from Keith Thompsons answer):

int *ptr = malloc(sizeof *ptr);
/* the value of ptr is now valid, possibly NULL */
if (ptr != NULL) 
{
    /* the value of ptr is valid and non-null */
    free(ptr);
    /* the value of ptr is now invalid */

    ... /* here operations in question */
}

List of allowed operations:

(To be completed and corrected by your answers and comments.)

  • Well defined: Take the size of the pointer variable. E.g. sizeof(ptr)
  • Well defined: Take the size of the dereferenced pointer (given it is not void *). E.g. sizeof(*ptr) (see comments of EOF and Jonathan Leffler ).
  • Well defined: Assignment of another (valid) value to the pointer (not to the referenced variable!). E.g. ptr = NULL;
  • Well defined: Accessing the representation of the Pointer (example from Keith Thompson's answer):

    unsigned char rep[sizeof ptr];
    memcpy(rep, &ptr, sizeof ptr); /* ok, accesses the representation */
                                   /* but not the value */
    

Operations that are not well-defined according to the standard:

(To be completed and corrected by your answers and comments.)

These operations are often treated as if they are well-defined on an invalid pointer, but are not well-defined according to the standard:

  • Undefined: Comparing the value of the pointer (even to a NULL-Pointer constant)
  • Undefined: conversion to an integral value

As with all undefined behaviour, you may get away with (ab)using the pointers on many machines, but the C Standard does not guarantee that you will get away with and there are (or once were) machines where such abuse of a pointer would lead to programs failing dramatically.

For the general rule, see Keith Thompson's answer — and the extensive comments below.

Answer 1:

任何使用无效指针的是未定义行为。

int *ptr = malloc(sizeof *ptr);
// the value of ptr is now valid, possibly NULL
if (ptr != NULL) {
    // the value of ptr is valid and non-null
    free(ptr);
    // the value of ptr is now invalid
    ptr; // UNDEFINED BEHAVIOR
}

引文: N1570 6.2.4p2:

一个指针的值变为不确定的时它指向的对象(或刚刚过去)达到其寿命的结束。

这可能是因为编译器将生成的表达式语句无代码ptr; ; 那是当然的,未定义行为的范围内。

指针对象的任何操作,不检索其值是(至少潜在地)明确定义的:

sizeof ptr;  // ok, doesn't use the value
sizeof *ptr; // ok, doesn't use the value, only the type
ptr = NULL;  // ok

您也可以访问指针对象的呈现 ,而无需访问它的价值:

unsigned char rep[sizeof ptr];
memcpy(rep, &ptr, sizeof ptr); // ok, accesses the representation
                               // but not the value

虽然没有太多你可以用做结果。



Answer 2:

这个问题是非常广阔的。 但是,为了回答您的具体方案:

int * myFunc(const int * const A, int * B)

如果这个功能用一个无效的指针值被称为那么它已经通过评估无效的指针值作为准备调用函数的部分引起未定义行为

所有“明确定义”你的子弹点都没有明确定义,因为一旦UB发生猫不能在包中放回去。



文章来源: Allowed operations on an possibly invalid pointer by the strict interpretation of the C Standard