I think there's an inconsistency in what's GCC is doing here. I concede the original example may invoke UB if the first write to malloc'ed region determines its type until free(). However, internally memory model in GCC allowes writes to dynamically change the effective type of the underlying storage: this is required to support C++ placement new, but the middle-end rules are the same for C and C++. So if you rewrite the original testcase in C++: #include <new> long foo(char *c1, char *c2) { long *p1 = new(c1) long; *p1 = 100; long long *p2 = new(c2) long long; *p2 = 200; long *p3 = new(c2) long; *p3 = 200; return *p1; } you get very surprising results: the optimization happens depending on the value of the last constant (switching 200 to 300 suppresses the transformation), or depending on whether long and long long match in size (using a 32-bit target suppresses the transformation). This points at least to an internal inconsistency in GCC if not to a real bug; I've opened a Bugzilla PR: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77745 . Alexander