if (w == 0 || h <= SIZE_MAX / w)
To me, that condition is just super-strange: if w is zero, the product w x h is zero too, so the entire allocation becomes pointless. Surely it should be: if (w != 0 && h <= SIZE_MAX / w)
or something? Having these kinds of discussions based on code that is confusing in itself just becomes too much, for me.