Skip to content

Commit c8a1d3c

Browse files
Ease reproducible bug report submission (#1816)
* Write KoreExecOptions to file * Create archive * Don't ignore error appending result * Kore.Log.withLogger: restrict to kore-exec * Fixed some integration tests * wip * Move report file removal * Revert changes in include.mk * cleanup * Test for file existence * Sort imports alphabetically * package.yaml: add version * Use temporary directory * Write result even if not requested * Follow frontend convention for file names * Copy koreProveOptions, koreSearchOptions and koreMergeOptions files * stylish * Use temp directory in handleSomeException too * wip kore-exec.sh * Create runnable shell script * Add report archives to .gitignore * Revert changes in .gitignore * Fixed some mistakes * Remove traceM * Remove changes in include.mk * stylish * Some renaming * wip * Module: Kore.BugReport * Adressed comments * Add BugReport module and clean include.mk * withMainLogger: Call continuation only once The continuation should be called only once. To enforce this fact, withMainLogger is rewritten to use ContT. * hlint * addressed comments * Cleanup * stylish * Addressed comments * Use stderr instead of stdout * stylish * Addressed comments * Restore include.mk * Fix typo Co-authored-by: Thomas Tuegel <[email protected]>
1 parent 42bc9d1 commit c8a1d3c

File tree

10 files changed

+501
-87
lines changed

10 files changed

+501
-87
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,4 @@ cabal.project.local
4747
/shell.local.nix
4848
/TAGS
4949
/.TAGS*
50+
report-*/

kore/app/exec/Main.hs

Lines changed: 198 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import Prelude.Kore
55
import Control.Monad.Catch
66
( MonadCatch
77
, SomeException
8+
, displayException
9+
, finally
810
, handle
911
, throwM
1012
)
@@ -18,6 +20,7 @@ import Data.Default
1820
import qualified Data.Foldable as Foldable
1921
import Data.Limit
2022
( Limit (..)
23+
, maybeLimit
2124
)
2225
import Data.List
2326
( intercalate
@@ -28,6 +31,7 @@ import Data.Semigroup
2831
)
2932
import Data.Text
3033
( Text
34+
, unpack
3135
)
3236
import qualified Data.Text as Text
3337
( null
@@ -56,7 +60,14 @@ import Options.Applicative
5660
)
5761
import qualified Options.Applicative as Options
5862
import System.Directory
59-
( doesFileExist
63+
( copyFile
64+
, doesFileExist
65+
, emptyPermissions
66+
, setOwnerExecutable
67+
, setOwnerReadable
68+
, setOwnerSearchable
69+
, setOwnerWritable
70+
, setPermissions
6071
)
6172
import System.Exit
6273
( ExitCode (..)
@@ -69,6 +80,10 @@ import System.IO
6980

7081
import qualified Data.Limit as Limit
7182
import Kore.Attribute.Symbol as Attribute
83+
import Kore.BugReport
84+
( BugReport (..)
85+
, parseBugReport
86+
)
7287
import Kore.Exec
7388
import Kore.IndexedModule.IndexedModule
7489
( VerifiedModule
@@ -102,9 +117,11 @@ import Kore.Log
102117
, LogMessage
103118
, SomeEntry (..)
104119
, WithLog
120+
, archiveDirectoryReport
105121
, logEntry
106122
, parseKoreLogOptions
107123
, runKoreLog
124+
, unparseKoreLogOptions
108125
)
109126
import Kore.Log.ErrorException
110127
( errorException
@@ -131,14 +148,17 @@ import Kore.Step.Search
131148
)
132149
import qualified Kore.Step.Search as Search
133150
import Kore.Step.SMT.Lemma
151+
import Kore.Step.Strategy
152+
( GraphSearchOrder (..)
153+
)
134154
import qualified Kore.Strategies.Goal as Goal
135155
import Kore.Strategies.Verification
136156
( Stuck (..)
137157
)
138158
import Kore.Syntax.Definition
139159
( Definition (Definition)
140160
, Module (Module)
141-
, ModuleName (ModuleName)
161+
, ModuleName (..)
142162
, Sentence (..)
143163
)
144164
import qualified Kore.Syntax.Definition as Definition.DoNotUse
@@ -154,11 +174,16 @@ import Pretty
154174
)
155175
import SMT
156176
( MonadSMT
177+
, TimeOut (..)
157178
)
158179
import qualified SMT
159180
import Stats
181+
import qualified System.IO.Temp as Temp
160182

161183
import GlobalMain
184+
import System.FilePath.Posix
185+
( (</>)
186+
)
162187

163188
{-
164189
Main module to run kore-exec
@@ -203,19 +228,19 @@ parseKoreSearchOptions =
203228

204229
parseSum :: String -> String -> String -> [(String, value)] -> Parser value
205230
parseSum metaName longName helpMsg options =
206-
option (readSum longName options)
231+
option (snd <$> readSum longName options)
207232
( metavar metaName
208233
<> long longName
209234
<> help (helpMsg <> ": " <> knownOptions)
210235
)
211236
where
212237
knownOptions = intercalate ", " (map fst options)
213238

214-
readSum :: String -> [(String, value)] -> Options.ReadM value
239+
readSum :: String -> [(String, value)] -> Options.ReadM (String, value)
215240
readSum longName options = do
216241
opt <- str
217242
case lookup opt options of
218-
Just val -> pure val
243+
Just val -> pure (opt, val)
219244
_ -> readerError (unknown opt ++ known)
220245
where
221246
knownOptions = intercalate ", " (map fst options)
@@ -232,7 +257,7 @@ applyKoreSearchOptions koreSearchOptions@(Just koreSearchOpts) koreExecOpts =
232257
{ koreSearchOptions
233258
, strategy =
234259
-- Search relies on exploring the entire space of states.
235-
priorityAllStrategy
260+
("all", priorityAllStrategy)
236261
, depthLimit = min depthLimit searchTypeDepthLimit
237262
}
238263
where
@@ -250,7 +275,7 @@ data Solver = Z3 | None
250275

251276
parseSolver :: Parser Solver
252277
parseSolver =
253-
option (readSum longName options)
278+
option (snd <$> readSum longName options)
254279
$ metavar "SOLVER"
255280
<> long longName
256281
<> help ("SMT solver for checking constraints: " <> knownOptions)
@@ -275,12 +300,13 @@ data KoreExecOptions = KoreExecOptions
275300
, smtSolver :: !Solver
276301
, breadthLimit :: !(Limit Natural)
277302
, depthLimit :: !(Limit Natural)
278-
, strategy :: !([Rewrite] -> Strategy (Prim Rewrite))
303+
, strategy :: !(String, [Rewrite] -> Strategy (Prim Rewrite))
279304
, koreLogOptions :: !KoreLogOptions
280305
, koreSearchOptions :: !(Maybe KoreSearchOptions)
281306
, koreProveOptions :: !(Maybe KoreProveOptions)
282307
, koreMergeOptions :: !(Maybe KoreMergeOptions)
283308
, rtsStatistics :: !(Maybe FilePath)
309+
, bugReport :: !BugReport
284310
}
285311

286312
-- | Command Line Argument Parser
@@ -334,6 +360,7 @@ parseKoreExecOptions =
334360
<*> optional parseKoreProveOptions
335361
<*> optional parseKoreMergeOptions
336362
<*> optional parseRtsStatistics
363+
<*> parseBugReport
337364
SMT.Config { timeOut = defaultTimeOut } = SMT.defaultConfig
338365
readSMTTimeOut = do
339366
i <- auto
@@ -348,7 +375,7 @@ parseKoreExecOptions =
348375
<> long "strategy"
349376
-- TODO (thomas.tuegel): Make defaultStrategy the default when it
350377
-- works correctly.
351-
<> value priorityAnyStrategy
378+
<> value ("any", priorityAnyStrategy)
352379
<> help "Select rewrites using STRATEGY."
353380
)
354381
where
@@ -392,6 +419,135 @@ parserInfoModifiers =
392419
\in PATTERN_FILE."
393420
<> header "kore-exec - an interpreter for Kore definitions"
394421

422+
unparseKoreSearchOptions :: KoreSearchOptions -> [String]
423+
unparseKoreSearchOptions (KoreSearchOptions _ bound searchType) =
424+
[ "--search searchFile.kore"
425+
, maybeLimit "" (\limit -> "--bound " <> show limit) bound
426+
, "--searchType " <> show searchType
427+
]
428+
429+
unparseKoreMergeOptions :: KoreMergeOptions -> [String]
430+
unparseKoreMergeOptions (KoreMergeOptions _ maybeBatchSize) =
431+
[ "--merge-rules mergeRules.kore"]
432+
<> maybe mempty ((:[]) . ("--merge-batch-size " <>) . show) maybeBatchSize
433+
434+
unparseKoreProveOptions :: KoreProveOptions -> [String]
435+
unparseKoreProveOptions
436+
( KoreProveOptions
437+
_
438+
(ModuleName moduleName)
439+
graphSearch
440+
bmc
441+
saveProofs
442+
)
443+
=
444+
[ "--prove spec.kore"
445+
, "--spec-module " <> unpack moduleName
446+
, "--graph-search "
447+
<> if graphSearch == DepthFirst then "depth-first" else "breadth-first"
448+
, if bmc then "--bmc" else ""
449+
, maybe "" ("--save-proofs " <>) saveProofs
450+
]
451+
452+
koreExecSh :: KoreExecOptions -> String
453+
koreExecSh
454+
( KoreExecOptions
455+
_
456+
patternFileName
457+
outputFileName
458+
mainModuleName
459+
(TimeOut timeout)
460+
smtPrelude
461+
smtSolver
462+
breadthLimit
463+
depthLimit
464+
strategy
465+
koreLogOptions
466+
koreSearchOptions
467+
koreProveOptions
468+
koreMergeOptions
469+
rtsStatistics
470+
_
471+
)
472+
=
473+
unlines $
474+
[ "#!/bin/sh"
475+
, "exec kore-exec \\"
476+
]
477+
<> (fmap (<> " \\") . filter (not . null)) options
478+
where
479+
options =
480+
[ if isJust koreProveOptions then "vdefinition.kore"
481+
else "definition.kore"
482+
, if isJust patternFileName then "--pattern pgm.kore" else ""
483+
, if isJust outputFileName then "--output result.kore" else ""
484+
, "--module " <> unpack (getModuleName mainModuleName)
485+
, maybeLimit "" (("--smt-timeout " <>) . show) timeout
486+
, maybe "" ("--smt-prelude " <>) smtPrelude
487+
, "--smt " <> fmap Char.toLower (show smtSolver)
488+
, maybeLimit "" (("--breadth " <>) . show) breadthLimit
489+
, maybeLimit "" (("--depth " <>) . show) depthLimit
490+
, "--strategy " <> fst strategy
491+
]
492+
<> unparseKoreLogOptions koreLogOptions
493+
<> maybe mempty unparseKoreSearchOptions koreSearchOptions
494+
<> maybe mempty unparseKoreProveOptions koreProveOptions
495+
<> maybe mempty unparseKoreMergeOptions koreMergeOptions
496+
<> maybe mempty ((:[]) . ("--rts-statistics " <>)) rtsStatistics
497+
498+
writeKoreSearchFiles :: FilePath -> KoreSearchOptions -> IO ()
499+
writeKoreSearchFiles reportFile KoreSearchOptions { searchFileName } =
500+
copyFile searchFileName $ reportFile <> "/searchFile.kore"
501+
502+
writeKoreMergeFiles :: FilePath -> KoreMergeOptions -> IO ()
503+
writeKoreMergeFiles reportFile KoreMergeOptions { rulesFileName } =
504+
copyFile rulesFileName $ reportFile <> "/mergeRules.kore"
505+
506+
writeKoreProveFiles :: FilePath -> KoreProveOptions -> IO ()
507+
writeKoreProveFiles reportFile KoreProveOptions { specFileName, saveProofs } = do
508+
copyFile specFileName $ reportFile <> "/spec.kore"
509+
Foldable.forM_ saveProofs $ flip copyFile (reportFile <> "/saveProofs.kore")
510+
511+
writeOptionsAndKoreFiles :: FilePath -> KoreExecOptions -> IO ()
512+
writeOptionsAndKoreFiles
513+
reportDirectory
514+
opts@KoreExecOptions
515+
{ definitionFileName
516+
, patternFileName
517+
, koreSearchOptions
518+
, koreProveOptions
519+
, koreMergeOptions
520+
}
521+
= do
522+
let shellScript = reportDirectory </> "kore-exec.sh"
523+
writeFile shellScript
524+
. koreExecSh
525+
$ opts
526+
let allPermissions =
527+
setOwnerReadable True
528+
. setOwnerWritable True
529+
. setOwnerExecutable True
530+
. setOwnerSearchable True
531+
setPermissions shellScript $ allPermissions emptyPermissions
532+
copyFile
533+
definitionFileName
534+
( reportDirectory
535+
</> if isJust koreProveOptions
536+
then "vdefinition.kore"
537+
else "definition.kore"
538+
)
539+
Foldable.forM_ patternFileName
540+
$ flip copyFile (reportDirectory </> "pgm.kore")
541+
Foldable.forM_
542+
koreSearchOptions
543+
(writeKoreSearchFiles reportDirectory)
544+
Foldable.forM_
545+
koreMergeOptions
546+
(writeKoreMergeFiles reportDirectory)
547+
Foldable.forM_
548+
koreProveOptions
549+
(writeKoreProveFiles reportDirectory)
550+
395551
-- TODO(virgil): Maybe add a regression test for main.
396552
-- | Loads a kore definition file and uses it to execute kore programs
397553
main :: IO ()
@@ -402,16 +558,24 @@ main = do
402558

403559
mainWithOptions :: KoreExecOptions -> IO ()
404560
mainWithOptions execOptions = do
405-
let KoreExecOptions { koreLogOptions } = execOptions
406-
exitCode <-
407-
runKoreLog koreLogOptions
408-
$ handle handleSomeException
409-
$ handle handleSomeEntry
410-
$ handle handleWithConfiguration go
411-
let KoreExecOptions { rtsStatistics } = execOptions
412-
Foldable.forM_ rtsStatistics $ \filePath ->
413-
writeStats filePath =<< getStats
414-
exitWith exitCode
561+
let KoreExecOptions { koreLogOptions, bugReport } = execOptions
562+
Temp.withSystemTempDirectory
563+
(fromMaybe "report" $ toReport bugReport)
564+
$ \tempDirectory -> do
565+
traceM tempDirectory
566+
exitCode <-
567+
runKoreLog tempDirectory koreLogOptions
568+
$ handle (handleSomeException tempDirectory)
569+
$ handle handleSomeEntry
570+
$ handle handleWithConfiguration go
571+
let KoreExecOptions { rtsStatistics } = execOptions
572+
Foldable.forM_ rtsStatistics $ \filePath ->
573+
writeStats filePath =<< getStats
574+
let reportPath = maybe tempDirectory ("./" <>) (toReport bugReport)
575+
finally
576+
(writeInReportDirectory tempDirectory)
577+
(archiveDirectoryReport tempDirectory reportPath)
578+
exitWith exitCode
415579
where
416580
KoreExecOptions { koreProveOptions } = execOptions
417581
KoreExecOptions { koreSearchOptions } = execOptions
@@ -423,9 +587,13 @@ mainWithOptions execOptions = do
423587
logEntry entry
424588
return $ ExitFailure 1
425589

426-
handleSomeException :: SomeException -> Main ExitCode
427-
handleSomeException someException = do
590+
handleSomeException :: FilePath -> SomeException -> Main ExitCode
591+
handleSomeException tempDirectory someException = do
428592
errorException someException
593+
lift
594+
$ writeFile
595+
(tempDirectory <> "/error.log")
596+
(displayException someException)
429597
return $ ExitFailure 1
430598

431599
handleWithConfiguration :: Goal.WithConfiguration -> Main ExitCode
@@ -453,6 +621,13 @@ mainWithOptions execOptions = do
453621
| otherwise =
454622
koreRun execOptions
455623

624+
writeInReportDirectory :: FilePath -> IO ()
625+
writeInReportDirectory tempDirectory = do
626+
when . isJust . toReport . bugReport
627+
<*> writeOptionsAndKoreFiles tempDirectory $ execOptions
628+
Foldable.forM_ (outputFileName execOptions)
629+
$ flip copyFile (tempDirectory <> "/outputFile.kore")
630+
456631
koreSearch :: KoreExecOptions -> KoreSearchOptions -> Main ExitCode
457632
koreSearch execOptions searchOptions = do
458633
let KoreExecOptions { definitionFileName } = execOptions
@@ -472,7 +647,7 @@ koreSearch execOptions searchOptions = do
472647
KoreSearchOptions { bound, searchType } = searchOptions
473648
config = Search.Config { bound, searchType }
474649
KoreExecOptions { breadthLimit, depthLimit, strategy } = execOptions
475-
strategy' = Limit.replicate depthLimit . strategy
650+
strategy' = Limit.replicate depthLimit . snd strategy
476651

477652
koreRun :: KoreExecOptions -> Main ExitCode
478653
koreRun execOptions = do
@@ -490,7 +665,7 @@ koreRun execOptions = do
490665
return exitCode
491666
where
492667
KoreExecOptions { breadthLimit, depthLimit, strategy } = execOptions
493-
strategy' = Limit.replicate depthLimit . strategy
668+
strategy' = Limit.replicate depthLimit . snd strategy
494669

495670
koreProve :: KoreExecOptions -> KoreProveOptions -> Main ExitCode
496671
koreProve execOptions proveOptions = do

0 commit comments

Comments
 (0)