Signed-cast overflow inverts version pragma range check
- Dominant language
- C++
- Stars
- 25.7k
- Forks
- 6.2k
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 29
Description
## Description
The version-pragma range comparison is **inverted** for version components in the range [2^31, 2^32).
Solidity version-pragma components are unsigned and the parser admits any value up to 2^32-1 (it only throws "Integer too large to be used in a version number." at `>= 2^32`, `liblangutil/SemVerHandler.cpp:275`), so a 10-digit component like `3000000000` is a legal pragma. However, the SemVer comparison casts each component to a signed `int` before subtracting:
```cpp
// liblangutil/SemVerHandler.cpp:116-118
didCompare = true;
cmp = static_cast(_version.numbers[i]) - static_cast(version.numbers[i]);
// ^ unsigned component >= 2^31 casts to a NEGATIVE int -> cmp sign flips
```
For a component in [2^31, 2^32) the `static_cast` of the unsigned value wraps to a negative int, so `cmp` gets the wrong sign and the entire range check is inverted.
On a 0.8.35 compiler, `pragma solidity >3000000000.0.0;` — an unsatisfiable constraint, since no compiler is version three-billion — compiles cleanly, while `pragma solidity <3000000000.0.0;` — satisfied by every compiler that will ever exist — is rejected with "Source file requires different compiler version". Components below 2^31 compare correctly (e.g. `>999999999.0.0` is rejected and `<999999999.0.0` is accepted), confirming the cause is the signed-cast overflow rather than the magnitude itself.
Expected: version components are unsigned, so the comparison should be unsigned (or a three-way compare) and the range check should hold for any component the parser accepts.
## Environment
- Compiler version: 0.8.35-develop.2026.5.5+commit.47b9dedd.Linux.g++
- Operating system: Linux Ubuntu Jammy
## Steps to Reproduce
```solidity
pragma solidity >3000000000.0.0; // unsatisfiable, yet COMPILES on 0.8.35
contract C {}
pragma solidity <3000000000.0.0; // always satisfiable, yet REJECTED
contract D {}
```
Control pair below 2^31 (compares correctly): `pragma solidity >999999999.0.0;` is rejected and `pragma solidity <999999999.0.0;` is accepted, proving the inversion is specific to the [2^31, 2^32) overflow range.
Contributor guide
Research direction
Start in liblangutil/SemVerHandler.cpp at lines 116-118 and inspect how version components are compared, then review the parser limit at line 275. Reproduce the issue with the two 3000000000.0.0 pragma examples and add coverage showing that accepted unsigned components preserve the expected range-check results.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, solidity
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100