packages feed

capnp-0.17.0.0: tests/PointerOOB.hs

{-# LANGUAGE DataKinds #-}

module PointerOOB (tests) where

import qualified Capnp as Capnp
import qualified Capnp.Errors as E
import qualified Capnp.Message as M
import qualified Capnp.Pointer as P
import qualified Capnp.Untyped as U
import Control.Category ((>>>))
import Control.Exception.Safe (try)
import Control.Monad.IO.Class (MonadIO (liftIO))
import qualified Data.ByteString as BS
import qualified Data.ByteString.Builder as BB
import qualified Data.ByteString.Lazy as LBS
import Data.Foldable (for_)
import Data.Function ((&))
import Test.Hspec

errPtrs :: [(P.Ptr, E.Error)]
errPtrs =
  [ ( P.ListPtr 0 (P.EltNormal P.Sz1 1),
      E.BoundsError {E.index = 2, E.maxIndex = 1}
    ),
    ( P.ListPtr 0 (P.EltNormal P.Sz32 4),
      E.BoundsError {E.index = 3, E.maxIndex = 1}
    ),
    ( P.ListPtr (-3) (P.EltNormal P.Sz1 1),
      E.BoundsError {E.index = -1, E.maxIndex = 1}
    ),
    ( P.ListPtr (-4) (P.EltNormal P.Sz1 1),
      E.BoundsError {E.index = -2, E.maxIndex = 1}
    ),
    ( P.StructPtr 0 1 0,
      E.BoundsError {E.index = 2, E.maxIndex = 1}
    ),
    ( P.StructPtr 0 0 1,
      E.BoundsError {E.index = 2, E.maxIndex = 1}
    ),
    ( P.StructPtr 0 1 1,
      E.BoundsError {E.index = 3, E.maxIndex = 1}
    )
  ]

wrapPtr :: P.Ptr -> BS.ByteString
wrapPtr p =
  [Just (P.StructPtr 0 0 1), Just p]
    & map (P.serializePtr >>> BB.word64LE)
    & mconcat
    & BB.toLazyByteString
    & LBS.toStrict

tests :: Spec
tests = describe "Test correct handling of out of bound pointers" $ do
  describe "pointers that go off the end of the message" $ do
    for_ errPtrs $ \(p, err) -> do
      it ("Should catch the issue for " <> show p) $ do
        let testPtrBounds :: P.Ptr -> Capnp.LimitT IO ()
            testPtrBounds p = do
              let msg = M.singleSegment $ Capnp.fromByteString (wrapPtr p)
              root <- U.rootPtr msg
              v <- try $ U.getPtr 0 root
              case v of
                Right _ -> fail "should have signaled an error"
                Left e -> liftIO $ e `shouldBe` err
        Capnp.evalLimitT maxBound (testPtrBounds p)