fix issue where libraries would get loaded at extreme timestamps and block numbers, also switch to the new hevm stripBytecodeMetadata (#510)

* fix issue where libraries would get loaded at extreme timestamps and block numbers, also switch to the new hevm stripBytecodeMetadata

* no longer doing cbor parsing

* added test

Co-authored-by: ggrieco-tob <gustavo.grieco@trailofbits.com>
pull/517/head
Will Song 4 years ago committed by GitHub
parent afb84d653a
commit 9149d95dda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      examples/solidity/basic/library.sol
  2. 16
      lib/Echidna/ABI.hs
  3. 13
      lib/Echidna/Exec.hs
  4. 10
      lib/Echidna/RPC.hs
  5. 17
      lib/Echidna/Solidity.hs
  6. 1
      lib/Echidna/Transaction.hs
  7. 1
      package.yaml
  8. 2
      src/test/Tests/Integration.hs

@ -1,23 +1,28 @@
library Test{
library Test {
struct Storage{
bool flag;
}
function set(Storage storage st) public{
function set(Storage storage st) public{
st.flag = true;
}
}
contract Contract{
contract Contract {
using Test for Test.Storage;
Test.Storage st;
function set() public{
function set() public{
st.set();
}
function echidna_library_call() external view returns (bool) {
function echidna_library_call() external view returns (bool) {
return (!st.flag);
}
function echidna_valid_timestamp() external view returns (bool) {
require(block.timestamp >= 1524785992 && block.number >= 4370000);
return (block.timestamp <= 1524785992 + 100 weeks && block.number < 4370000 + 10000000);
}
}

@ -8,19 +8,14 @@
module Echidna.ABI where
import Codec.CBOR.Read (deserialiseFromBytes)
import Codec.CBOR.Term (decodeTerm)
import Control.Lens
import Control.Monad (join, liftM2, liftM3, foldM, replicateM)
import Control.Monad.Catch (MonadThrow(..))
import Control.Monad.State.Class (MonadState, gets)
import Control.Monad.State (evalStateT)
import Control.Monad.Random.Strict (MonadRandom, getRandom, getRandoms, getRandomR, uniformMay)
import Data.Binary.Get (runGet, getWord16be)
import Data.Bool (bool)
import Data.ByteString (ByteString)
import Data.ByteString.Lazy (fromStrict)
import Data.Either (isRight)
import Data.Foldable (toList)
import Data.Has (Has(..))
import Data.Hashable (Hashable(..))
@ -308,14 +303,3 @@ genAbiCallM abi = genWithDict (fmap toList . view wholeCalls) (traverse $ traver
genInteractionsM :: (MonadState x m, Has GenDict x, MonadRandom m, MonadThrow m)
=> NE.NonEmpty SolSignature -> m SolCall
genInteractionsM l = genAbiCallM =<< rElem l
-- | Given a solc bytecode strip off the metadata from the end
stripBytecodeMetadata :: ByteString -> ByteString
stripBytecodeMetadata bc
| BS.length cl /= 2 = bc
| BS.length h >= cl' && (isRight . deserialiseFromBytes decodeTerm $ fromStrict cbor) = bc'
| otherwise = bc
where l = BS.length bc
(h, cl) = BS.splitAt (l - 2) bc
cl' = fromIntegral . runGet getWord16be . fromStrict $ cl
(bc', cbor) = BS.splitAt (BS.length h - cl') h

@ -11,20 +11,20 @@ import Control.Lens
import Control.Monad.Catch (Exception, MonadThrow(..))
import Control.Monad.State.Strict (MonadState, execState)
import Data.Has (Has(..))
import Data.Map.Strict (Map)
import Data.Map.Strict (Map, fromList)
import Data.Maybe (fromMaybe)
import Data.Set (Set)
import EVM
import EVM.Op (Op(..))
import EVM.Exec (exec)
import EVM.Exec (exec, vmForEthrunCreation)
import EVM.Solidity (stripBytecodeMetadata)
import qualified Data.ByteString as BS
import qualified Data.Map as M
import qualified Data.Set as S
import Echidna.ABI (stripBytecodeMetadata)
import Echidna.Transaction
import Echidna.Types.Tx (TxCall(..), Tx, TxResult(..), call, dst)
import Echidna.Types.Tx (TxCall(..), Tx, TxResult(..), call, dst, initialTimestamp, initialBlockNumber)
-- | Broad categories of execution failures: reversions, illegal operations, and ???.
data ErrorClass = RevertE | IllegalE | UnknownE
@ -123,3 +123,8 @@ traceCoverage = do
v <- use hasLens
let c = v ^. state . code
hasLens <>= [readOp (BS.index c $ v ^. state . pc) c]
initialVM :: VM
initialVM = vmForEthrunCreation mempty & block . timestamp .~ initialTimestamp
& block . number .~ initialBlockNumber
& env . contracts .~ fromList [] -- fixes weird nonce issues

@ -16,15 +16,14 @@ import Control.Monad.Reader.Class (MonadReader(..))
import Control.Monad.State.Strict (MonadState, execStateT, runStateT, get, put)
import Data.Aeson (FromJSON(..), (.:), withObject, eitherDecodeFileStrict)
import Data.Binary.Get (runGetOrFail)
import Data.ByteString.Char8 (ByteString, empty)
import Data.ByteString.Char8 (ByteString)
import Data.Has (Has(..))
import Data.Map (fromList)
import Data.Maybe (maybe)
import Data.Text.Encoding (encodeUtf8)
import EVM
import EVM.ABI (AbiType(..), getAbi)
import EVM.Concrete (w256)
import EVM.Exec (exec, vmForEthrunCreation)
import EVM.Exec (exec)
import EVM.Types (Addr, W256)
import Text.Read (readMaybe)
@ -88,10 +87,9 @@ loadEthenoBatch ts fp = do
(Left e) -> throwM $ EthenoException e
(Right (ethenoInit :: [Etheno])) -> do
-- Execute contract creations and initial transactions,
let blank = vmForEthrunCreation empty & env . contracts .~ fromList []
initVM = foldM (execEthenoTxs ts) Nothing ethenoInit
let initVM = foldM (execEthenoTxs ts) Nothing ethenoInit
(addr, vm') <- runStateT initVM blank
(addr, vm') <- runStateT initVM initialVM
case addr of
Nothing -> throwM $ EthenoException "Could not find a contract with echidna tests"
Just a -> execStateT (liftSH . loadContract $ a) vm'

@ -32,8 +32,8 @@ import System.Process (StdStream(..), readCreateProcessWithExitCode,
import System.IO (openFile, IOMode(..))
import System.Exit (ExitCode(..))
import System.Directory (findExecutable)
import Echidna.ABI (encodeSig, hashSig, stripBytecodeMetadata, fallback)
import Echidna.Exec (execTx)
import Echidna.ABI (encodeSig, hashSig, fallback)
import Echidna.Exec (execTx, initialVM)
import Echidna.RPC (loadEthenoBatch)
import Echidna.Types.Signature (FunctionHash, SolSignature, SignatureMap)
import Echidna.Types.Tx (TxConf, TxCall(..), Tx(..), initialTimestamp, initialBlockNumber)
@ -43,8 +43,7 @@ import Echidna.Processor
import EVM hiding (contracts)
import qualified EVM (contracts)
import EVM.ABI
import EVM.Exec (vmForEthrunCreation)
import EVM.Solidity hiding (stripBytecodeMetadata)
import EVM.Solidity
import EVM.Types (Addr)
import EVM.Concrete (w256)
@ -163,7 +162,7 @@ loadLibraries :: (MonadIO m, MonadThrow m, MonadReader x m, Has SolConf x)
=> [SolcContract] -> Addr -> Addr -> VM -> m VM
loadLibraries [] _ _ vm = return vm
loadLibraries (l:ls) la d vm = loadLibraries ls (la + 1) d =<< loadRest
where loadRest = execStateT (execTx $ Tx (SolCreate $ l ^. creationCode) d la 8000030 0 0 (initialTimestamp, initialBlockNumber)) vm
where loadRest = execStateT (execTx $ Tx (SolCreate $ l ^. creationCode) d la 8000030 0 0 (0, 0)) vm
-- | Generate a string to use as argument in solc to link libraries starting from addrLibrary
linkLibraries :: [String] -> String
@ -200,7 +199,7 @@ loadSpecified name cs = do
unless q . putStrLn $ "Analyzing contract: " <> c ^. contractName . unpacked
-- Local variables
(SolConf ca d ads bala balc pref _ _ libs _ fp ma ch bm fs) <- view hasLens
SolConf ca d ads bala balc pref _ _ libs _ fp ma ch bm fs <- view hasLens
-- generate the complete abi mapping
let bc = c ^. creationCode
@ -219,7 +218,9 @@ loadSpecified name cs = do
-- Set up initial VM, either with chosen contract or Etheno initialization file
-- need to use snd to add to ABI dict
blank' <- maybe (pure (vmForEthrunCreation bc)) (loadEthenoBatch (fst <$> tests)) fp
blank' <- maybe (pure initialVM)
(loadEthenoBatch $ fst <$> tests)
fp
let blank = populateAddresses (NE.toList ads |> d) bala blank'
& env . EVM.contracts %~ sans 0x3be95e4159a131e56a84657c4ad4d43ec7cd865d -- fixes weird nonce issues
@ -235,7 +236,7 @@ loadSpecified name cs = do
Just (t,_) -> throwM $ TestArgsFound t -- Test args check
Nothing -> do
vm <- loadLibraries ls addrLibrary d blank
let transaction = unless (isJust fp) $ void . execTx $ Tx (SolCreate bc) d ca 8000030 0 (w256 $ fromInteger balc) (initialTimestamp, initialBlockNumber)
let transaction = unless (isJust fp) $ void . execTx $ Tx (SolCreate bc) d ca 8000030 0 (w256 $ fromInteger balc) (0, 0)
vm' <- execStateT transaction vm
case currentContract vm' of
Just _ -> return (vm', neFuns, fst <$> tests, abiMapping)

@ -23,6 +23,7 @@ import Data.Maybe (catMaybes)
import EVM hiding (value)
import EVM.ABI (abiCalldata, abiValueType)
import EVM.Concrete (Word(..), w256)
import EVM.Solidity (stripBytecodeMetadata)
import EVM.Types (Addr)
import qualified System.Directory as SD

@ -16,7 +16,6 @@ dependencies:
- brick <= 0.46
- base16-bytestring
- bytestring
- cborg
- containers
- data-dword
- data-has

@ -80,6 +80,8 @@ integrationTests = testGroup "Solidity Integration Testing"
[ ("echidna_balance failed", passed "echidna_balance") ]
, testContract "basic/library.sol" (Just "basic/library.yaml")
[ ("echidna_library_call failed", solved "echidna_library_call") ]
, testContract "basic/library.sol" (Just "basic/library.yaml")
[ ("echidna_valid_timestamp failed", passed "echidna_valid_timestamp") ]
, testContract "basic/fallback.sol" Nothing
[ ("echidna_fallback failed", solved "echidna_fallback") ]
, testContract "basic/darray.sol" Nothing

Loading…
Cancel
Save