never executed always true always false
1 {-# LANGUAGE RecordWildCards, LambdaCase #-}
2 module GHCi.Leak
3 ( LeakIndicators
4 , getLeakIndicators
5 , checkLeakIndicators
6 ) where
7
8 import Control.Monad
9 import Data.Bits
10 import Foreign.Ptr (ptrToIntPtr, intPtrToPtr)
11 import GHC
12 import GHC.Ptr (Ptr (..))
13 import GHCi.Util
14 import GHC.Driver.Env
15 import GHC.Driver.Ppr
16 import GHC.Utils.Outputable
17 import GHC.Unit.Module.ModDetails
18 import GHC.Unit.Home.ModInfo
19 import GHC.Platform (target32Bit)
20 import GHC.Linker.Types
21 import Prelude
22 import System.Mem
23 import System.Mem.Weak
24 import GHC.Types.Unique.DFM
25
26 -- Checking for space leaks in GHCi. See #15111, and the
27 -- -fghci-leak-check flag.
28
29 data LeakIndicators = LeakIndicators [LeakModIndicators]
30
31 data LeakModIndicators = LeakModIndicators
32 { leakMod :: Weak HomeModInfo
33 , leakIface :: Weak ModIface
34 , leakDetails :: Weak ModDetails
35 , leakLinkable :: Maybe (Weak Linkable)
36 }
37
38 -- | Grab weak references to some of the data structures representing
39 -- the currently loaded modules.
40 getLeakIndicators :: HscEnv -> IO LeakIndicators
41 getLeakIndicators hsc_env =
42 fmap LeakIndicators $
43 forM (eltsUDFM (hsc_HPT hsc_env)) $ \hmi@HomeModInfo{..} -> do
44 leakMod <- mkWeakPtr hmi Nothing
45 leakIface <- mkWeakPtr hm_iface Nothing
46 leakDetails <- mkWeakPtr hm_details Nothing
47 leakLinkable <- mapM (`mkWeakPtr` Nothing) hm_linkable
48 return $ LeakModIndicators{..}
49
50 -- | Look at the LeakIndicators collected by an earlier call to
51 -- `getLeakIndicators`, and print messasges if any of them are still
52 -- alive.
53 checkLeakIndicators :: DynFlags -> LeakIndicators -> IO ()
54 checkLeakIndicators dflags (LeakIndicators leakmods) = do
55 performGC
56 forM_ leakmods $ \LeakModIndicators{..} -> do
57 deRefWeak leakMod >>= \case
58 Nothing -> return ()
59 Just hmi ->
60 report ("HomeModInfo for " ++
61 showSDoc dflags (ppr (mi_module (hm_iface hmi)))) (Just hmi)
62 deRefWeak leakIface >>= \case
63 Nothing -> return ()
64 Just miface -> report ("ModIface:" ++ moduleNameString (moduleName (mi_module miface))) (Just miface)
65 deRefWeak leakDetails >>= report "ModDetails"
66 forM_ leakLinkable $ \l -> deRefWeak l >>= report "Linkable"
67 where
68 report :: String -> Maybe a -> IO ()
69 report _ Nothing = return ()
70 report msg (Just a) = do
71 addr <- anyToPtr a
72 putStrLn ("-fghci-leak-check: " ++ msg ++ " is still alive at " ++
73 show (maskTagBits addr))
74
75 tagBits
76 | target32Bit (targetPlatform dflags) = 2
77 | otherwise = 3
78
79 maskTagBits :: Ptr a -> Ptr a
80 maskTagBits p = intPtrToPtr (ptrToIntPtr p .&. complement (shiftL 1 tagBits - 1))