Skip to content

Commit ae83cf2

Browse files
authored
Fix some issues revealed by static analysis (#960)
I had a run with [stan](https://github.com/kowainik/stan) an I have uploaded the [stan.html](https://maudoux.be/stan_original.html) report. The tool is a bit heavy on strict data and avoiding unnamed black holes in pattern matches. But at least it made me remove some uses of Unsafe. Another useful but weird case is that it highlights issues with the list type which theoretically allows infinite lists. Functions like length may thus not terminate. In our case moving to slists is not a good idea, but Vectors may represent better the lists we handle. But it is not worth switching if we create vectors from lists.
1 parent 976b7f2 commit ae83cf2

File tree

2 files changed

+38
-45
lines changed

2 files changed

+38
-45
lines changed

src/Nix/Builtins.hs

Lines changed: 36 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ where
2525

2626

2727
import Prelude hiding ( traceM )
28-
import Relude.Unsafe as Unsafe
2928
import Nix.Utils
3029
import Control.Comonad ( Comonad )
3130
import Control.Monad ( foldM )
@@ -83,7 +82,11 @@ import System.Posix.Files ( isRegularFile
8382
, isDirectory
8483
, isSymbolicLink
8584
)
86-
import Text.Regex.TDFA
85+
import Text.Regex.TDFA ( Regex
86+
, makeRegex
87+
, matchOnceText
88+
, matchAllText
89+
)
8790

8891

8992
-- This is a big module. There is recursive reuse:
@@ -156,10 +159,10 @@ instance Comonad f => Ord (WValue t f m) where
156159

157160
-- ** Helpers
158161

159-
nVNull
162+
nvNull
160163
:: MonadNix e t f m
161164
=> NValue t f m
162-
nVNull = nvConstant NNull
165+
nvNull = nvConstant NNull
163166

164167
mkNVBool
165168
:: MonadNix e t f m
@@ -221,8 +224,8 @@ attrsetGet k s =
221224

222225
data VersionComponent
223226
= VersionComponentPre -- ^ The string "pre"
224-
| VersionComponentString Text -- ^ A string other than "pre"
225-
| VersionComponentNumber Integer -- ^ A number
227+
| VersionComponentString !Text -- ^ A string other than "pre"
228+
| VersionComponentNumber !Integer -- ^ A number
226229
deriving (Show, Read, Eq, Ord)
227230

228231
versionComponentToString :: VersionComponent -> Text
@@ -315,20 +318,13 @@ splitMatches numDropped (((_, (start, len)) : captures) : mts) haystack =
315318
caps = nvList (f <$> captures)
316319
f (a, (s, _)) =
317320
bool
318-
nVNull
321+
nvNull
319322
(thunkStr a)
320323
(s >= 0)
321324

322325
thunkStr :: Applicative f => ByteString -> NValue t f m
323326
thunkStr s = nvStrWithoutContext $ decodeUtf8 s
324327

325-
elemAt :: [a] -> Int -> Maybe a
326-
elemAt ls i =
327-
list
328-
Nothing
329-
(pure . Unsafe.head)
330-
(drop i ls)
331-
332328
hasKind
333329
:: forall a e t f m
334330
. (MonadNix e t f m, FromValue a m (NValue t f m))
@@ -481,7 +477,7 @@ unsafeGetAttrPosNix nvX nvY =
481477
case (x, y) of
482478
(NVStr ns, NVSet _ apos) ->
483479
maybe
484-
(pure nVNull)
480+
(pure nvNull)
485481
toValue
486482
(M.lookup (stringIgnoreContext ns) apos)
487483
_xy -> throwError $ ErrorCall $ "Invalid types for builtins.unsafeGetAttrPosNix: " <> show _xy
@@ -583,19 +579,19 @@ foldl'Nix f z xs = foldM go z =<< fromValue @[NValue t f m] xs
583579
where
584580
go b a = (`callFunc` a) =<< callFunc f b
585581

586-
headNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)
582+
headNix :: forall e t f m. MonadNix e t f m => NValue t f m -> m (NValue t f m)
587583
headNix =
588-
list
584+
maybe
589585
(throwError $ ErrorCall "builtins.head: empty list")
590-
(pure . Unsafe.head)
591-
<=< fromValue
586+
(pure)
587+
. viaNonEmpty head <=< fromValue @[NValue t f m]
592588

593-
tailNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)
589+
tailNix :: forall e t f m. MonadNix e t f m => NValue t f m -> m (NValue t f m)
594590
tailNix =
595-
list
591+
maybe
596592
(throwError $ ErrorCall "builtins.tail: empty list")
597-
(pure . nvList . Unsafe.tail)
598-
<=< fromValue
593+
(pure . nvList)
594+
. viaNonEmpty tail <=< fromValue @[NValue t f m]
599595

600596
splitVersionNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)
601597
splitVersionNix v =
@@ -674,24 +670,19 @@ matchNix pat str =
674670
(toValue $ makeNixStringWithoutContext t)
675671
(not $ Text.null t)
676672

677-
maybe
678-
(pure nVNull)
679-
(\case
680-
("", sarr, "") ->
681-
do
682-
let s = fst <$> elems sarr
683-
nvList <$>
684-
traverse
685-
mkMatch
686-
(bool
687-
id -- (length <= 1) allowed & passes-through here the full string
688-
Unsafe.tail
689-
(length s > 1)
690-
s
691-
)
692-
_ -> (pure nVNull)
693-
)
694-
(matchOnceText re s)
673+
case matchOnceText re s of
674+
Just ("", sarr, "") ->
675+
do
676+
let submatches = fst <$> elems sarr
677+
nvList <$>
678+
traverse
679+
mkMatch
680+
(case submatches of
681+
[] -> []
682+
[a] -> [a]
683+
_:xs -> xs -- return only the matched groups, drop the full string
684+
)
685+
_ -> pure nvNull
695686

696687
splitNix
697688
:: forall e t f m
@@ -929,7 +920,7 @@ elemAtNix xs n =
929920
maybe
930921
(throwError $ ErrorCall $ "builtins.elem: Index " <> show n' <> " too large for list of length " <> show (length xs'))
931922
pure
932-
(elemAt xs' n')
923+
(xs' !!? n')
933924

934925
genListNix
935926
:: forall e t f m
@@ -1022,7 +1013,7 @@ replaceStringsNix tfrom tto ts =
10221013
maybePrefixMatch
10231014

10241015
where
1025-
-- When prefix matched something - returns (match, replacement, reminder)
1016+
-- When prefix matched something - returns (match, replacement, remainder)
10261017
maybePrefixMatch :: Maybe (Text, NixString, Text)
10271018
maybePrefixMatch = formMatchReplaceTailInfo <$> find ((`Text.isPrefixOf` input) . fst) fromKeysToValsMap
10281019
where
@@ -1526,7 +1517,7 @@ fromJSONNix nvjson =
15261517
NInt
15271518
(floatingOrInteger n)
15281519
A.Bool b -> pure $ mkNVBool b
1529-
A.Null -> pure nVNull
1520+
A.Null -> pure nvNull
15301521

15311522
toJSONNix :: MonadNix e t f m => NValue t f m -> m (NValue t f m)
15321523
toJSONNix = (fmap nvStr . nvalueToJSONNixString) <=< demand
@@ -1844,7 +1835,7 @@ builtinsList = sequence
18441835
, add2 Normal "match" matchNix
18451836
, add2 Normal "mul" mulNix
18461837
, add0 Normal "nixPath" nixPathNix
1847-
, add0 Normal "null" (pure nVNull)
1838+
, add0 Normal "null" (pure nvNull)
18481839
, add Normal "parseDrvName" parseDrvNameNix
18491840
, add2 Normal "partition" partitionNix
18501841
--, add Normal "path" path

src/Nix/Options.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
{-# LANGUAGE StrictData #-}
2+
13
-- | Definitions & defaults for the CLI options
24
module Nix.Options where
35

0 commit comments

Comments
 (0)