Skip to content

Fixing checking assert failure #753

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Conversation

msooseth
Copy link
Collaborator

@msooseth msooseth commented May 20, 2025

Description

As per discussion on the public matrix channel and the issue #751 we have a problem with revert()/revert("message")/assertintest` mode. Fixes:

  • require(a==b, "str") is no longer considered a FAIL
  • revert(string) is no longer considered a FAIL

As before, all assert-s are considered a FAIL. Also, as before, revert() is not considered a fail.

The badVault code seems to PASS now. It used to fail on the require(stuff, "string") which should not have been a cause for FAIL. It may actually be a good vault, and so maybe the PASS is correct. We can also fix badVault to be actually bad, or it may also be that hevm is incorrect, though that seems unlikely?

Checklist

  • tested locally
  • added automated tests
  • updated the docs
  • updated the changelog

@msooseth msooseth force-pushed the fixing-forge-assert-check branch from 5b3a960 to 31a10d8 Compare May 20, 2025 14:56
@msooseth msooseth marked this pull request as ready for review May 20, 2025 15:04
@msooseth msooseth force-pushed the fixing-forge-assert-check branch 4 times, most recently from e0a2c13 to bfcd1b0 Compare May 21, 2025 13:15
@msooseth msooseth requested a review from blishko May 21, 2025 13:16
@msooseth
Copy link
Collaborator Author

OK, I think this is finally ready for review :) I added a number of test cases, and removed badVault. We can come back to badVault later.

@msooseth msooseth force-pushed the fixing-forge-assert-check branch 2 times, most recently from 578fe0a to 99c8f7a Compare May 21, 2025 13:48
require(bool,string) was also considered a FAIL, and revert(string)
also, etc. Also added a number of tests for all of these.
@msooseth msooseth force-pushed the fixing-forge-assert-check branch from 99c8f7a to 1a6a476 Compare May 22, 2025 10:18
-- We need to drop the selector (4B), the offset value (aligned to 32B), and the length of the string (aligned to 32B)
-- NOTE: assertTrue/assertFalse does not have the double colon after "assertion failed"
let assertFail = selector "Error(string)" `BS.isPrefixOf` b && "assertion failed" `BS.isPrefixOf` (BS.drop (4+32+32) b)
in if assertFail || b == panicMsg 0x01 then PBool False
else PBool True
b -> b ./= ConcreteBuf (panicMsg 0x01)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should run the prefix check in the symbolic case too

@msooseth
Copy link
Collaborator Author

msooseth commented May 22, 2025

The commit be2a5eb now also handles the symbolic case when the prefix is a concrete "assertion failed" of the symbolic string.

We currently don't handle when the string returned doesn't have a concrete prefix matching "assertion failed"

Adding a note about checkAssertions

Ooops
@msooseth msooseth force-pushed the fixing-forge-assert-check branch from c16aca9 to be2a5eb Compare May 26, 2025 12:49
@@ -508,6 +508,7 @@ getExpr solvers c signature' concreteArgs opts = do
- 0x51: If you call a zero-initialized variable of internal function type.

see: https://docs.soliditylang.org/en/v0.8.6/control-structures.html?highlight=Panic#panic-via-assert-and-error-via-require
NOTE: does not deal with e.g. `assertEq()`
-}
checkAssertions :: [Word256] -> Postcondition s
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used anywhere? can we either fix it or delete it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or is there a reason to only check for direct calls to assert in solidity?

@@ -210,9 +212,12 @@ symRun opts@UnitTestOptions{..} vm (Sig testName types) = do
Success _ _ _ store -> if opts.checkFailBit then PNeg (failed store) else PBool True
Failure _ _ (Revert msg) -> case msg of
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the sake of completeness, we should also handle the invalid opcode (0xFE) which was raised by solc < 0.4.

symbolicFail e =
let text = V.fromList $ map (fromIntegral . ord) "assertion failed"
panic = e == ConcreteBuf (panicMsg 0x01)
assertFail = V.take (length text) (Expr.concretePrefix e) == text
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is sound? What if we have a symbolic prefix that could still be "assertion failed"?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants