low

Built-in `shift()` function will fail if passed a negative integer at compile...

Reward

Total

455.95 USDC

Selected
455.95 USDC
Selected Submission

Built-in shift() function will fail if passed a negative integer at compile time

Severity

Low Risk

Relevant GitHub Links

https://github.com/vyperlang/vyper/blob/b01cd686aa567b32498fefd76bd96b0597c6f099/vyper/builtins/functions.py#L1451-L1466

Summary

The built-in shift() function accepts an INT256 as an input, which are accounted for and work fine at runtime. However, there is a compile time check that causes a revert if a negative literal is passed to the function.

Vulnerability Details

In the evaluate() method, which is used when shift() is evaluated at compile time, there is the following check:

if value < 0 or value >= 2**256:
    raise InvalidLiteral("Value out of range for uint256", node.args[0])

However, the function is intended to accept INT256 as an argument:

_inputs = [("x", (UINT256_T, INT256_T)), ("_shift_bits", IntegerT.any())]

This is properly handled in the build_IR() method, but fails when evaluate() is called at compile time.

Impact

Contracts that shift a negative literal and attempt to evaluate the expression at compile time will fail to compile.

Tools Used

Manual Review

Recommendations

The ideal option would be to update the evaluate() method to handle negative integers.

Alternatively, given the shift() function is deprecated and may not justify the extra work, the easiest solution is to simply raise UnfoldableNote for values between type(int256).min and 0, which will skip evaluation and leave the function to be evaluated at runtime.