> Doesn't null-pointer-dereference always crash the application?
No. It's undefined behaviour, it may do anything or nothing.
> Is it only an undefined-behavior because program-must-crash is not the explicitly required by these languages' specs?
I don't understand the question here. It's undefined behaviour because the spec says it's undefined behaviour, which is some combination of because treating it as impossible allows many optimisation opportunities and because of historical accidents.
Compilers are allowed to assume undefined behavior doesn't happen, and dereferencing an invalid pointer is undefined behavior. You don't have to like it, but that's how it is.
No, it does not always crash. This is a common misconception caused by thinking about the problem on the MMU (hardware) level, where reading a null pointer predictably results in a page fault. If this was the only thing we had to contend with, then yes, it would immediately terminate the process, cutting down the risk of a null pointer dereference to just a crash.
The problem is instead in software - it is undefined behavior, so most compilers may optimize it out and write code that assumes it never happens, which often causes nightmarish silent corruption / control flow issues rather than immediately crashing. These optimizations are common enough for it to be a relatively common failure mode.
There is a bit of nuance that on non-MMU hardware such as microcontrollers and embedded devices, reading null pointers does not actually trigger an error on a hardware level, but instead actually gives you access to the 0 position on memory. This is usually either a feature (because it's a nice place to put global data) or a gigantic pitfall of its own (because it's the most likely place for accidental corruption to cause a serious problem, and reading it inadvertently may reveal sensitive global state).
Only if that memory page is unmapped, and only if the optimizer doesn't detect that it's a null pointer and start deleting verification code because derefing null is UB, and UB is assumed to never happen.
No. It's undefined behaviour, it may do anything or nothing.
> Is it only an undefined-behavior because program-must-crash is not the explicitly required by these languages' specs?
I don't understand the question here. It's undefined behaviour because the spec says it's undefined behaviour, which is some combination of because treating it as impossible allows many optimisation opportunities and because of historical accidents.