3

In the context of another question there was some discussion on whether it was allowed (i.e. would or would not introduce implementation defined or undefined behavior) to cast int** to void** and subsequently assign a value to the dereferenced void*. This brings me to my question on the interpretation of the C11 standard

6.2.5 (28) A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. ...
6.3.2.3 (1) A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
6.3.2.3 (7) ... When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. ...

My question is whether this

int* intptr = NULL;
void* dvoidptr = &intptr; /* 6.3.2.3 (1) */
*(void**)dvoidptr = malloc(sizeof *intptr); /* using 6.3.2.3 (1) */

conforms with the standard or not? It seems strange to me, but I cannot find a conclusive line of argument why not. void* to void** is guaranteed by 6.3.2.3 and 6.2.5 together with 6.3.2.3 help with the alignment.

Community
  • 1
  • 1
merlin
  • 136
  • 5
  • 1
    This is just the same thing: it violates strict aliasing. End of story. – The Paramagnetic Croissant Jun 03 '14 at 08:41
  • 1
    Where exactly is this specified in the standard? According to 6.2.5 (28) `void*` basically is a character type. And C11 Std. part 6.5 (7) explicitly says _An object shall have its stored value accessed only by an lvalue expression that has one of the following types: ..[list of types].. - a character type_. So maybe you should not be so fast in dismissing this question/discussion. – merlin Jun 03 '14 at 08:56
  • 3
    In C99, 6.5.7: the behavior is undefined if you access an object through an lvalue of incompatible type (except character types). Since `void *` is not `char *`, maybe you should not be so fast assuming things that aren't written in the standard. – The Paramagnetic Croissant Jun 03 '14 at 09:35
  • and, btw, this is exactly what's written in the last paragraph of the answer. [Also, read this.](http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule) – The Paramagnetic Croissant Jun 03 '14 at 09:36
  • I was in no way saying that it was not in the standard, only that people are more inclined to believe you if you were to use citations. – merlin Jun 03 '14 at 09:51

1 Answers1

4

Code is not valid.

See the emphasis:

6.3.2.3 (1) A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.

You are converting int** to void* (fine), and then to different type void** (not ok). C gives no quarantee that you can safely convert void* to anything other than the original type (aside from converting to char *)

In addition, *(void**)dvoidptr results in void* when in reality there is int*. What if, for example, sizeof(void*) == 2 and sizeof(int*) == 1? You can convert void* pointer to other type, but you cannot reinterpret it directly as other type.

user694733
  • 15,208
  • 2
  • 42
  • 68
  • First of all thank you for the afford of not only saying its wrong that's it. Now to the comment: That is kind of the point, it is open to interpretation. The first sentence in 6.3.2.3 (1) says that I in fact can convert `void*` to `void**` (if `void*` can be interpreted as an object that is). Which leaves the question whether the rules are transitive or not. The argument with `sizeof(void*) > sizeof(int*)` seems wrong to me because of 6.3.2.3 (7) and 6.2.5 (28). – merlin Jun 03 '14 at 10:05
  • @merlin you think you are safe because you use a `void*` in between the two other pointers. That is not the case. – this Jun 03 '14 at 10:10
  • @merlin No, you can convert `void*` to `void**` *only* if pointer was originally `void**`, which in this case isn't. As for `sizeof` issue, point here is the *conversion*; pointers of different do not have to have same representation (except for `void*` and `char*`), when you assign to `void*` to other pointer type or back, it is compilers reponsibility insert code which coverts it to the other representation, if needed on that platform. – user694733 Jun 03 '14 at 10:14