Maybe I'm being overly paranoid, but this does introduce some nontrivial calculations in what can be rather fast paths. I'd rather store the pointer separately. Or, at this point, it'd probably be fine to use aligned_alloc().
More to the point, though... is this going to reliably solve the bug? What are we storing in the heap header that's unimportant enough that it can be overwritten?
If so, we should have a comment explicitly saying "this has to be a heap allocation so that it can be corrupted", so nobody tries to change this again in the future.
If not, then I think we should explicitly work around this somehow.