Skip to main content
Sigvex

Inheritance Order Remediation

Order base contracts from most general to most derived so C3 linearization resolves overrides as intended.

Inheritance Order Remediation

Overview

When several parents define the same function, Solidity uses C3 linearization to decide which one runs. The order in which base contracts are listed determines that resolution. An incorrect order can dispatch to the wrong parent’s implementation and can shift storage layout between parents in ways that surprise the author.

Related Detector: Inheritance Order

Before (Vulnerable)

// Author expects ParentA.withdraw() to win, but the order resolves to ParentB
contract Vault is ParentB, ParentA {
    // withdraw() resolves to ParentB.withdraw()
}

After (Fixed)

// List bases from most base-like to most derived; the right-most wins ties
contract Vault is ParentA, ParentB {
    // Use super and explicit overrides to make resolution deliberate
    function withdraw() public override(ParentA, ParentB) {
        super.withdraw();
    }
}

Solidity requires base contracts to be listed from “most base-like” to “most derived,” and the right-most parent takes precedence in the linearization. Writing an explicit override(...) that names every conflicting parent forces the author to confront the ambiguity, and super makes the call chain explicit rather than implicit.

Alternative Mitigations

  • Use explicit override(Base1, Base2) annotations for every function defined by more than one parent so the compiler enforces a deliberate choice.
  • Keep state-bearing base contracts to a minimum and document their intended order to avoid storage layout surprises.
  • Favor composition over deep multiple inheritance where the resolution order is hard to reason about.

Common Mistakes

  • Listing bases from most-derived to most-base, which inverts the precedence the author expected.
  • Adding a new base contract in the middle of the list and silently changing which override wins for unrelated functions.
  • Relying on implicit resolution instead of super and explicit override, hiding the actual call chain.

References