handle zero-size allocations correctly

The `malloc` family of functions may return a null pointer for a
zero-size allocation, which should not be interpreted as an
out-of-memory error.

If the implementation does not return a null pointer, then handling
this will result in memory savings for zero-size types.

Closes #11634