Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disarm fails when instrumented code fails to compile #119

Closed
wolflo opened this issue Nov 17, 2021 · 8 comments · Fixed by #133
Closed

Disarm fails when instrumented code fails to compile #119

wolflo opened this issue Nov 17, 2021 · 8 comments · Fixed by #133
Assignees
Labels
bug Something isn't working

Comments

@wolflo
Copy link

wolflo commented Nov 17, 2021

If you have a contract that compiles before being instrumented but fails to compile after being instrumented, scribble will successfully arm the contract but fail to disarm it. This can leave a bit of a mess of armed files to clean up before you can fix or diagnose the issue.

Example

Shadowed.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IShadower {
    function shadowed(uint256 a) external;
    function shadowed(uint256 a, uint256 b) external;
}

/// #invariant {:msg "I0"} 0 == 0;
contract Scribbled {
    function entry() external {
        IShadower(address(0)).shadowed(1);
    }
}
solc Shadowed.sol

Succeeds.

scribble Shadowed.sol --output-mode files --arm

Succeeds, but leaves an instrumented Shadowed.sol that fails to compile.

In this case, it is because the function pointer passed to the _callsite_ method cannot discern between the two versions of IShadower.shadowed(). As far as I know, this is a limitation of solidity rather than a scribble bug, but used here as an example.

scribble Shadowed.sol --output-mode files --disarm

Because the newly instrumented Shadowed.sol won't compile, this fails and leaves armed files that must be sorted out manually or reverted to a previous commit.

Feature Request

  • If it's not necessary to compile the armed contracts before disarming, that seems like an easy fix. Maybe this could be behind a --disarm --force flag.
  • Attempt to compile the armed contracts and revert instrumenting if they fail to compile.
@wolflo
Copy link
Author

wolflo commented Nov 17, 2021

An issue related to the reason the instrumented version of this contract won't compile: ethereum/solidity#12296

@cd1m0
Copy link
Collaborator

cd1m0 commented Nov 18, 2021

Thanks for the report @wolflo . Yeah, this needs to be fixed. The tricky bit is making sure we don't miss any files. This can be a problem, as in certain cases (e.g. when there are contract-wide invariants) scribble may instrument contracts even under node_modules/. A semi-clean solution would be for scribble to leave enough "bread crubms" during instrumentation. One thing that can serve the role of "bread crumbs" is the instrumentation metadata json file. Currently its only optionally emited using the --instrumentation-metadata-file command line option. So one way to achieve the desired result might be:

  1. Scribble always emits an instrumentation metadata file with --arm. By default its in some location (e.g. .instrumentation.md.json, and users can optionally change that location with --instrumentation-metadata-file).

  2. When dis-arming scribble looks for the instrumentation metadata in its default location (or a user can override this with --instrumentation-metadata-file), and uses the data in that to find the modified files

The only risk with this solution is that the metadata file somehow gets out-of-sync with the instrumented files in the repo

@cd1m0 cd1m0 self-assigned this Nov 18, 2021
@cd1m0 cd1m0 added the bug Something isn't working label Nov 18, 2021
@JoranHonig
Copy link
Collaborator

@cd1m0 maybe we can include a series of comments on top of instrumented files indicating that they're auto generated and that they shouldn't be edited directly (only after it has been disarmed).

@cd1m0
Copy link
Collaborator

cd1m0 commented Nov 22, 2021

@cd1m0 maybe we can include a series of comments on top of instrumented files indicating that they're auto generated and that they shouldn't be edited directly (only after it has been disarmed).

I think I expressed myself incorrectly - I was worried about .original files being modified somehow? Or left over from an earlier arming and overwriting new code with stale code? This shouldn't happen under normal user patterns, just trying to think of edge cases.

@wolflo
Copy link
Author

wolflo commented Nov 22, 2021

What is the reason for compiling the armed contracts before disarming?

@cd1m0
Copy link
Collaborator

cd1m0 commented Nov 23, 2021

After discussion with @blitz-1306 we decided:

  1. Add a special marker comment to instrumented files saying "this is a scribble instrumented file. Don't touch it .."

  2. We will require --instrumentation-metadata-file to be specified when we do --arm and we can't detect a project root. Project root is detected by scanning the tree up from the least common ancestor of all the target files/directories, looking for signs of project root: 'package.json', 'hardhat.config.ts', 'truffle-config.json', and whatever brownie does

  3. When instrumenting with --arm, we will FIRST check if there already exists an instrumentation metadata file (as specified by the above algorithm), and NEXT we will check if the files in that instrumentation metadata files are still instrumented. The way we check if files in the instrumentation metadata file are instrumented is by looking for the marker specified in 0. (TODO: Decide if we should also check if .instrumented and .original files exists with the same base name. Decide what to do in this case). If instrumented files are detected, error should be thrown saying that the person should disarm first.

@blitz-1306
Copy link
Contributor

This would require a fix in solc-typed-ast to respect StructuredDocumentation nodes in SourceUnit children during AST-to-source writing. Currently they are ignored.

@blitz-1306
Copy link
Contributor

blitz-1306 commented Dec 1, 2021

@wolflo

What is the reason for compiling the armed contracts before disarming?

I would say major reason is (and always been a big pain) an import resolution. We can resolve imports by relying on Solc callbacks while compiling files (unless breadcrumbs idea, suggested by @cd1m0). There are a lot of effort done to make that work:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants