Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Is `void **` an exception to strict aliasing rules?

Basically, is this code legal when strict aliasing is enabled?

void f(int *pi) {
    void **pv = (void **) π
    *pv = NULL;
}

Here, we access an object of one type (int*) through a pointer of another type (pointer to void *), so I would say that it is indeed a strict-aliasing violation.

But a sample attempting to highlight the undefined behavior makes me doubt (even if it does not prove that it is legal).

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

First, if we alias int * and char *, we can get different values depending on the optimization level (so it is definitely a strict-aliasing violation):

#include <stdio.h>

static int v = 100;

void f(int **a, char **b) {
    *a = &v;
    *b = NULL;
    if (*a)
        // *b == *a (NULL)
        printf("Should never be printed: %i\n", **a);
}

int main() {
    int data = 5;
    int *a = &data;
    f(&a, (char **) &a);
    return 0;
}
$ gcc a.c && ./a.out
$ gcc -O2 -fno-strict-aliasing a.c && ./a.out
$ gcc -O2 a.c && ./a.out
Should never be printed: 100

But the very same sample with void ** instead of char ** does not exhibit the undefined behavior:

#include <stdio.h>

static int v = 100;

void f(int **a, void **b) {
    *a = &v;
    *b = NULL;
    if (*a)
        // *b == *a (NULL)
        printf("Should never be printed: %i\n", **a);
}

int main() {
    int data = 5;
    int *a = &data;
    f(&a, (void **) &a);
    return 0;
}
$ gcc a.c && ./a.out
$ gcc -O2 -fno-strict-aliasing a.c && ./a.out
$ gcc -O2 a.c && ./a.out

Is it just accidental? Or is there an explicit exception in the standard forvoid **?

Or maybe just the compilers handle void ** specifically because in practice (void **) &a is too common in the wild?

>Solution :

Basically, is this code legal when strict aliasing is enabled?

No. The effective type of pi is int* but you lvalue access the pointer variable through a void*. De-referencing a pointer to give an access which doesn’t correspond to the effective type of the object is a strict aliasing violation – with some exceptions, this isn’t one.

In your second example, both parameters to the function are set to point at an object of effective type int* which is done here: f(&a, (char **) &a);. Therefore *b inside the function is indeed a strict aliasing violation, since you are using a char* type for the access.

In your third example you do the same but with a void*. This is also a strict aliasing violation. There is nothing special with void* or void** in this context.

Why your compilers exhibits a certain form of undefined behavior in some situations is not very meaningful to speculate about. Although void* must by definition be convertible to/from any other object pointer type, so they very likely have the representation internally, even though that’s not an explicit requirement from the standard.

Also you are using -fno-strict-aliasing which turns off various pointer aliasing-based optimizations. If you wish to provoke strange and unexpected results, you shouldn’t use that option.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading