Through C cast magic it's possible to put a raw void pointer into a variable of non-void pointer type. It is fine - generally, it's possible to put anything into anywhere by temporarily re-interpreting the anywhere. We cast it back to the correct type during load - with the help of StoreManager::CastRetrievedVal().
The attached example demonstrates that we're not casting the retrieved value pedantically enough when it comes to retrieving pointer values. In fact, we don't cast pointers-to-pointers at all because SValBuilder doesn't know how to do that or even that it needs to do that at all.
In this patch i perform the pointer cast manually for the situation that causes the crash. Performing the cast more carefully in other cases is possible, but i didn't manage to produce an observable effect (the second test passes just fine without it, and works correctly).
I cannot put the castRegion() call into SValBuilder because SValBuilder doesn't have access to StoreManager when doing casts. We really need to decouple this stuff and make a single good function for handling casts, because understanding how current code for pointer casts works is a nightmare.
@NoQ why is this true for both x86_64 and i386?
On x86_64 sizeof(int *) == 8 and sizeof(int) == 4. This means that (*((int *)(&x))) = (int)&u; writes to the lower 4 bytes of x and leaves the upper 4 bytes uninitialized. See this godbolt example. If I compile and run this function on my machine it segfaults.
On i386 sizeof(int *) == 4 and sizeof(int) == 4, so on that platform this example is correct. See on godbolt.
In the x86_64 case don't we want the analyzer to report a warning a instead, as on that platform u is only partially initialized?