After issuing many /time set night
commands, I can tell you the waking-location algorithm for Minecraft. This presumably also affects your spawn point.
Two locations are checked, and if they fail to select an acceptable location the pillow-location is used regardless of consequences of picking this location. An acceptable location is on the same level as the bed, and has two transparent-non-solid blocks above it (i.e. you will be standing next to the bed without your head or body embedded in something that’s killing you).
The process is the same for each of the two locations:
Sweep x-1 to x+1: Sweep z-1 to z+1: if the location is acceptable, we're done
The locations are checked in the order: pillow-part-of-bed, non-pillow-part-of-bed. The effect is:
From the Minecraft wiki:
For a bed to be usable as a spawn point, the player must be able to stand next to the bed at the same level as it. There must be a solid block at the same ‘floor’ level as the bed, with 2 transparent blocks of space (for example, air) for the player to stand in, in one of the ten blocks that surround the bed. It doesn’t matter if the bed itself has blocks above it.