Skip to content

Commit

Permalink
Allow disabling Slither (#1327)
Browse files Browse the repository at this point in the history
This allows explicitly disabling Slither with a new `--disable-slither` command-line flag
or `disableSlither` configuration option. A blinking, red warning will be shown in the UI
when Slither is disabled or otherwise failed, to disuade people from fuzzing without it.

Closes #1318
  • Loading branch information
elopez authored Dec 3, 2024
1 parent 0db6f4c commit 740e950
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 4 deletions.
1 change: 1 addition & 0 deletions lib/Echidna/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ instance FromJSON EConfigWithUsage where
<*> v ..:? "balanceContract" ..!= 0
<*> v ..:? "codeSize" ..!= 0xffffffff
<*> v ..:? "prefix" ..!= "echidna_"
<*> v ..:? "disableSlither" ..!= False
<*> v ..:? "cryticArgs" ..!= []
<*> v ..:? "solcArgs" ..!= ""
<*> v ..:? "solcLibs" ..!= []
Expand Down
14 changes: 12 additions & 2 deletions lib/Echidna/SourceAnalysis/Slither.hs
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,13 @@ instance FromJSON SlitherInfo where

-- Slither processing
runSlither :: FilePath -> SolConf -> IO SlitherInfo
runSlither fp solConf = do
findExecutable "slither" >>= \case
runSlither fp solConf = if solConf.disableSlither
then do
hPutStrLn stderr $
"WARNING: Slither was explicitly disabled. Echidna uses Slither (https://github.com/crytic/slither)"
<> " to perform source analysis, which makes fuzzing more effective. You should enable it."
pure emptySlitherInfo
else findExecutable "slither" >>= \case
Nothing -> do
hPutStrLn stderr $
"WARNING: slither not found. Echidna uses Slither (https://github.com/crytic/slither)"
Expand Down Expand Up @@ -177,3 +182,8 @@ runSlither fp solConf = do

emptySlitherInfo :: SlitherInfo
emptySlitherInfo = SlitherInfo mempty mempty mempty mempty mempty [] [] []

isEmptySlitherInfo :: Maybe SlitherInfo -> Bool
isEmptySlitherInfo (Just (SlitherInfo _ _ _ _ _ [] [] [])) = True
isEmptySlitherInfo Nothing = True
isEmptySlitherInfo _ = False
1 change: 1 addition & 0 deletions lib/Echidna/Types/Solidity.hs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ data SolConf = SolConf
, balanceContract :: Integer -- ^ Initial balance of contract to test
, codeSize :: Integer -- ^ Max code size for deployed contratcs (default 0xffffffff)
, prefix :: Text -- ^ Function name prefix used to denote tests
, disableSlither :: Bool -- ^ Whether or not to skip running Slither
, cryticArgs :: [String] -- ^ Args to pass to crytic
, solcArgs :: String -- ^ Args to pass to @solc@
, solcLibs :: [String] -- ^ List of libraries to load, in order.
Expand Down
2 changes: 2 additions & 0 deletions lib/Echidna/UI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import Echidna.Campaign (runWorker, spawnListener)
import Echidna.Output.Corpus (saveCorpusEvent)
import Echidna.Output.JSON qualified
import Echidna.Server (runSSEServer)
import Echidna.SourceAnalysis.Slither (isEmptySlitherInfo)
import Echidna.Types.Campaign
import Echidna.Types.Config
import Echidna.Types.Corpus qualified as Corpus
Expand Down Expand Up @@ -126,6 +127,7 @@ ui vm dict initialCorpus cliSelectedContract = do
, timeStarted = now
, timeStopped = Nothing
, now = now
, slitherSucceeded = not $ isEmptySlitherInfo env.slitherInfo
, fetchedContracts = mempty
, fetchedSlots = mempty
, fetchedDialog = B.dialog (Just $ str " Fetched contracts/slots ") Nothing 80
Expand Down
16 changes: 15 additions & 1 deletion lib/Echidna/UI/Widgets.hs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ data UIState = UIState
, timeStarted :: LocalTime
, timeStopped :: Maybe LocalTime
, now :: LocalTime
, slitherSucceeded :: Bool
, fetchedContracts :: Map Addr (Maybe Contract)
, fetchedSlots :: Map Addr (Map W256 (Maybe W256))
, fetchedDialog :: B.Dialog () Name
Expand All @@ -65,7 +66,8 @@ data UIStateStatus = Uninitialized | Running

attrs :: A.AttrMap
attrs = A.attrMap (V.white `on` V.black)
[ (attrName "failure", fg V.brightRed)
[ (attrName "alert", fg V.brightRed `V.withStyle` V.blink `V.withStyle` V.bold)
, (attrName "failure", fg V.brightRed)
, (attrName "maximum", fg V.brightBlue)
, (attrName "bold", fg V.white `V.withStyle` V.bold)
, (attrName "tx", fg V.brightWhite)
Expand All @@ -79,6 +81,9 @@ attrs = A.attrMap (V.white `on` V.black)
bold :: Widget n -> Widget n
bold = withAttr (attrName "bold")

alert :: Widget n -> Widget n
alert = withAttr (attrName "alert")

failure :: Widget n -> Widget n
failure = withAttr (attrName "failure")

Expand Down Expand Up @@ -184,6 +189,8 @@ summaryWidget env uiState =
str ("Corpus size: " <> show uiState.corpusSize <> " seqs")
<=>
str ("New coverage: " <> timeElapsed uiState uiState.lastNewCov <> " ago") <+> fill ' '
<=>
slitherWidget uiState.slitherSucceeded
rightSide =
padLeft (Pad 1)
(rpcInfoWidget uiState.fetchedContracts uiState.fetchedSlots env.chainId)
Expand Down Expand Up @@ -217,6 +224,13 @@ rpcInfoWidget contracts slots chainId =
let successful = filter isJust fetches
in outOf (length successful) (length fetches)

slitherWidget
:: Bool
-> Widget Name
slitherWidget slitherSucceeded = if slitherSucceeded
then success (str "Slither succeeded")
else alert (str "No Slither in use!")

outOf :: Int -> Int -> Widget n
outOf n m =
let style = if n == m then success else failure
Expand Down
6 changes: 5 additions & 1 deletion src/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ data Options = Options
, cliDeployer :: Maybe Addr
, cliSender :: [Addr]
, cliSeed :: Maybe Int
, cliDisableSlither :: Bool
, cliCryticArgs :: Maybe String
, cliSolcArgs :: Maybe String
, cliSymExec :: Maybe Bool
Expand Down Expand Up @@ -210,6 +211,8 @@ options = Options
<*> optional (option auto $ long "seed"
<> metavar "SEED"
<> help "Run with a specific seed.")
<*> switch (long "disable-slither"
<> help "Disable running Slither.")
<*> optional (option str $ long "crytic-args"
<> metavar "ARGS"
<> help "Additional arguments to use in crytic-compile for the compilation of the contract to test.")
Expand Down Expand Up @@ -276,7 +279,8 @@ overrideConfig config Options{..} = do
}

overrideSolConf solConf = solConf
{ solcArgs = fromMaybe solConf.solcArgs cliSolcArgs
{ disableSlither = cliDisableSlither || solConf.disableSlither
, solcArgs = fromMaybe solConf.solcArgs cliSolcArgs
, cryticArgs = maybe solConf.cryticArgs words cliCryticArgs
, sender = if null cliSender then solConf.sender else Set.fromList cliSender
, deployer = fromMaybe solConf.deployer cliDeployer
Expand Down
2 changes: 2 additions & 0 deletions tests/solidity/basic/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ balanceAddr: 0xffffffff
balanceContract: 0
#codeSize max code size for deployed contratcs (default 0xffffffff)
codeSize: 0xffffffff
#whether or not to disable running slither (default false, uses slither)
disableSlither: false
#solcArgs allows special args to solc
solcArgs: ""
#solcLibs is solc libraries
Expand Down

0 comments on commit 740e950

Please sign in to comment.