Skip to content

Commit

Permalink
Simplify saving tx result in coverage (#1158)
Browse files Browse the repository at this point in the history
  • Loading branch information
arcz authored Jan 7, 2024
1 parent f6e8fbb commit 937102b
Showing 1 changed file with 12 additions and 15 deletions.
27 changes: 12 additions & 15 deletions lib/Echidna/Exec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import Echidna.Symbolic (forceBuf)
import Echidna.Transaction
import Echidna.Types (ExecException(..), Gas, fromEVM, emptyAccount)
import Echidna.Types.Config (Env(..), EConfig(..), UIConf(..), OperationMode(..), OutputFormat(Text))
import Echidna.Types.Coverage (CoverageInfo)
import Echidna.Types.Signature (getBytecodeMetadata, lookupBytecodeMetadata)
import Echidna.Types.Solidity (SolConf(..))
import Echidna.Types.Tx (TxCall(..), Tx, TxResult(..), call, dst, initialTimestamp, initialBlockNumber, getResult)
Expand Down Expand Up @@ -237,7 +238,7 @@ execTx
execTx vm tx = runStateT (execTxWith (fromEVM exec) tx) vm

-- | A type alias for the context we carry while executing instructions
type CoverageContext = (Bool, Maybe (BS.ByteString, Int))
type CoverageContext = (Bool, Maybe (VMut.IOVector CoverageInfo, Int))

-- | Execute a transaction, logging coverage at every step.
execTxWithCov
Expand All @@ -257,17 +258,13 @@ execTxWithCov tx = do

-- Update the last valid location with the transaction result
grew' <- liftIO $ case lastLoc of
Just (meta, pc) -> do
cov <- readIORef covRef
case Map.lookup meta cov of
Nothing -> pure False -- shouldn't happen
Just vec -> do
let txResultBit = fromEnum $ getResult $ fst r
VMut.read vec pc >>= \case
(opIx, depths, txResults) | not (txResults `testBit` txResultBit) -> do
VMut.write vec pc (opIx, depths, txResults `setBit` txResultBit)
pure True -- we count this as new coverage
_ -> pure False
Just (vec, pc) -> do
let txResultBit = fromEnum $ getResult $ fst r
VMut.read vec pc >>= \case
(opIx, depths, txResults) | not (txResults `testBit` txResultBit) -> do
VMut.write vec pc (opIx, depths, txResults `setBit` txResultBit)
pure True -- we count this as new coverage
_ -> pure False
_ -> pure False

pure (r, grew || grew')
Expand Down Expand Up @@ -314,7 +311,7 @@ execTxWithCov tx = do

VMut.write vec' pc (opIx, fromIntegral depth, 0 `setBit` fromEnum Stop)

writeIORef covContextRef (True, Just (meta, pc))
writeIORef covContextRef (True, Just (vec', pc))
else do
-- TODO: should we collect the coverage here? Even if there is no
-- bytecode for external contract, we could have a "virtual" location
Expand All @@ -328,9 +325,9 @@ execTxWithCov tx = do
VMut.read vec pc >>= \case
(_, depths, results) | depth < 64 && not (depths `testBit` depth) -> do
VMut.write vec pc (opIx, depths `setBit` depth, results `setBit` fromEnum Stop)
writeIORef covContextRef (True, Just (meta, pc))
writeIORef covContextRef (True, Just (vec, pc))
_ ->
modifyIORef' covContextRef $ \(new, _) -> (new, Just (meta, pc))
modifyIORef' covContextRef $ \(new, _) -> (new, Just (vec, pc))

-- | Get the VM's current execution location
currentCovLoc vm = (vm.state.pc, fromMaybe 0 $ vmOpIx vm, length vm.frames)
Expand Down

0 comments on commit 937102b

Please sign in to comment.