There are may things in C which cause UB.
Most of them are ok to do so, but there are several ones where implementation-defined behaviour would be more logical. Let me have an example:
Concerning the <<
operator,
If E1 has a signed type and nonnegative value, and E1 × 2 E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
That means that
signed char r = 0x40;
r <<= 2;
is UB where IB would IMO be more logical.
Is an implementation allowed to define what happens here?
From the C standard:
A conforming hosted implementation shall accept any strictly conforming program... A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any strictly conforming program.
In other words, the implementation is free to guarantee a particular behavior for what would otherwise be undefined behavior. It just can't do it in a way which changes defined behavior.