argotorg / argotorg/solidity

Overriding a virtual modifier can add state access to an inherited pure/view function

Open
#16,931 0 comments 0 reactions 0 assignees View on GitHub
bug :bug: codegen error medium effort medium impact must have
Dominant language
C++
Stars
25.7k
Forks
6.2k
Avg merge
2d 19h
Merged PRs (30d)
29

Description

`ViewPureChecker` validates a function body against the modifier it is
statically bound to. `ModifierDefinition::resolveVirtual()` later re-resolves
the modifier over the most derived contract's linearization, and modifiers
carry no state mutability for `OverrideChecker` to compare.

So a derived contract can override a virtual modifier with one that writes
storage, and every inherited `pure` or `view` function using that modifier
silently gains state access. The compiler reports no error and no warning, and
the ABI still advertises the function as `pure`.

## Reproducer

```solidity
contract A {
uint256 public s;
modifier m() virtual { _; }
function f() public pure m returns (uint256) { return 1; }
}

contract D is A {
modifier m() override { s = 5; _; }
}
```

Compiles cleanly, with only the existing deprecation warning about virtual
modifiers. Deploying `D` and calling it gives:

```
f() -> 1
s() -> 5 // a pure function wrote storage
```

`solc --abi` reports `"stateMutability": "pure"` for `D.f`. The generated IR
for `D` shows `fun_f` calling the modifier wrapper, which contains the
`sstore`.

### As a syntax test

```solidity
contract A {
uint256 public s;
modifier m() virtual { _; }
function f() public pure m returns (uint256) { return 1; }
}

contract D is A {
modifier m() override { s = 5; _; }
}
// ----
// TypeError : (375-410): Overriding modifier accesses state, but "A.f", which uses it, is declared "pure".
```

## Expected behaviour

A compile-time error.

Contributor guide

Open the contributing guide

Research direction

Start with ViewPureChecker, ModifierDefinition::resolveVirtual(), and OverrideChecker to trace how modifier state mutability is validated and later re-resolved. Turn the supplied derived-contract reproducer into a compiler syntax test and verify that compilation reports the expected TypeError instead of emitting D.f as pure.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, solidity
Domain
blockchain, compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.