Yes, there is at least one situation where overflow can occur. I don't know about underflows though.
When you divide the minimum of a signed type by -1, you get the mirror image of that number in the unsigned part, but the unsigned type only goes up to that number minus 1.
function div_overflow() public pure returns (int16 result) {
int16 x = type(int16).min;
int16 y = -1;
// Overflows because doesn't fit in int16
result = x / y;
}
In Solidity, signed numbers start at -1, while unsigned numbers start at 0. Read more about. Read more about two's complement in the Solidity docs.
Update: looks like this is specified in the docs:
The expression type(int).min
/ (-1) is the only case where division causes an overflow. In checked arithmetic mode, this will cause a failing assertion, while in wrapping mode, the value will be type(int).min
.