Commit 10b30d7d by Zachary Snow

detect infinite include loops

parent 5cc4dce0
...@@ -16,7 +16,7 @@ module Language.SystemVerilog.Parser.Preprocess ...@@ -16,7 +16,7 @@ module Language.SystemVerilog.Parser.Preprocess
import Control.Monad.Except import Control.Monad.Except
import Control.Monad.State.Strict import Control.Monad.State.Strict
import Data.Char (ord) import Data.Char (ord)
import Data.List (dropWhileEnd, tails, isPrefixOf, findIndex) import Data.List (dropWhileEnd, tails, isPrefixOf, findIndex, intercalate)
import Data.Maybe (isJust, fromJust) import Data.Maybe (isJust, fromJust)
import System.Directory (findFile) import System.Directory (findFile)
import System.FilePath (dropFileName) import System.FilePath (dropFileName)
...@@ -37,6 +37,7 @@ data PP = PP ...@@ -37,6 +37,7 @@ data PP = PP
, ppCondStack :: [Cond] -- if-else cascade state , ppCondStack :: [Cond] -- if-else cascade state
, ppIncludePaths :: [FilePath] -- folders to search for includes , ppIncludePaths :: [FilePath] -- folders to search for includes
, ppMacroStack :: [[(String, String)]] -- arguments for in-progress macro expansions , ppMacroStack :: [[(String, String)]] -- arguments for in-progress macro expansions
, ppIncludeStack :: [(FilePath, Env)] -- in-progress includes for loop detection
} deriving (Eq, Show) } deriving (Eq, Show)
-- keeps track of the state of an if-else cascade level -- keeps track of the state of an if-else cascade level
...@@ -72,7 +73,7 @@ preprocess includePaths env path = do ...@@ -72,7 +73,7 @@ preprocess includePaths env path = do
if path == "-" if path == "-"
then getContents then getContents
else loadFile path else loadFile path
let initialState = PP contents [] (Position path 1 1) path env [] includePaths [] let initialState = PP contents [] (Position path 1 1) path env [] includePaths [] [(path, env)]
result <- runExceptT $ execStateT preprocessInput initialState result <- runExceptT $ execStateT preprocessInput initialState
return $ case result of return $ case result of
Left msg -> Left msg Left msg -> Left msg
...@@ -172,6 +173,27 @@ getBuffer = do ...@@ -172,6 +173,27 @@ getBuffer = do
p <- getPosition p <- getPosition
return (x, p) return (x, p)
-- mark the start of an include for include loop detection
pushIncludeStack :: FilePath -> PPS ()
pushIncludeStack path = do
stack <- gets ppIncludeStack
env <- gets ppEnv
let entry = (path, env)
let stack' = entry : stack
if elem entry stack then do
let first : rest = reverse $ map fst stack'
lexicalError $ "include loop: " ++ show first ++ " includes "
++ intercalate ", which includes " (map show rest)
else
modify $ \s -> s { ppIncludeStack = stack' }
-- mark the end of an include for include loop detection
popIncludeStack :: PPS ()
popIncludeStack = do
stack <- gets ppIncludeStack
let stack' = tail stack
modify $ \s -> s { ppIncludeStack = stack' }
-- Push a condition onto the top of the preprocessor condition stack -- Push a condition onto the top of the preprocessor condition stack
pushCondStack :: Cond -> PPS () pushCondStack :: Cond -> PPS ()
pushCondStack c = getCondStack >>= setCondStack . (c :) pushCondStack c = getCondStack >>= setCondStack . (c :)
...@@ -713,12 +735,14 @@ handleDirective macrosOnly = do ...@@ -713,12 +735,14 @@ handleDirective macrosOnly = do
-- find and load the included file -- find and load the included file
let filename = init $ tail quotedFilename let filename = init $ tail quotedFilename
includePath <- includeSearch filename includePath <- includeSearch filename
pushIncludeStack includePath
includeContent <- liftIO $ loadFile includePath includeContent <- liftIO $ loadFile includePath
-- pre-process the included file -- pre-process the included file
setFilePath includePath setFilePath includePath
setBuffer (includeContent, Position includePath 1 1) setBuffer (includeContent, Position includePath 1 1)
preprocessInput preprocessInput
-- resume processing the original file -- resume processing the original file
popIncludeStack
setFilePath fileFollow setFilePath fileFollow
setBuffer bufFollow setBuffer bufFollow
......
// pattern: include loop: "include_loop_1\.sv" includes "\./include_loop_1\.sv", which includes "\./include_loop_1\.sv"
`include "include_loop_1.sv"
// pattern: include loop: "include_loop_2\.sv" includes "\./include_loop_1\.sv", which includes "\./include_loop_1\.sv"
`include "include_loop_1.sv" // other file
`ifdef GUARD_5
module top;
wire x;
endmodule
`elsif GUARD_4
`define GUARD_5
`include "include_self.sv"
`elsif GUARD_3
`define GUARD_4
`include "include_self.sv"
`elsif GUARD_2
`define GUARD_3
`include "include_self.sv"
`elsif GUARD_1
`define GUARD_2
`include "include_self.sv"
`elsif GUARD_0
`define GUARD_1
`include "include_self.sv"
`else
`define GUARD_0
`include "include_self.sv"
`endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment