Skip to content

Coverage instrumentation interactions with OpenZeppelin code patterns #8214

@kanej

Description

@kanej

Our migration branch of OpenZeppelin/contracts has tests that pass if run in the standard way, but which fail if you run with coverage enabled.

There are several issue at play here including some tests failing due to the Fusaka gas cap: #7807

But a large number of tests appear to be an underlying issue. Specifically, that the staticcall added by instrumentation resets the the returndata buffer (see EIP-211: "Upon executing any call-like opcode, the buffer is cleared (its size is set to zero)"). However OpenZeppelin leverages RETURNDATASIZE and RETURNDATACOPY, leading to the following pattern when combined with coverage:

__HardhatCoverage.sendHit(0x9fe2d70...);
bool success = LowLevelCall.callNoReturn(target, value, data);
__HardhatCoverage.sendHit(0xfc00d70...);   //  ← STATICCALL clobbers RETURNDATA here
if (LowLevelCall.returnDataSize() > 0) {   //  ← always 0 now
    LowLevelCall.bubbleRevert();
} else {
    revert Errors.FailedCall();             //  ← always taken
}

Reproduction Steps

Clone the https://github.com/NomicFoundation/openzeppelin-contracts repo then checkout the chore/update-to-hardhat-3-4 branch:

npm install

npx hardhat test mocha # runs successfully
npx hardhat test mocha --coverage # fails

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions