diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,3 +1,7 @@
+0.10.10.0 TBD
+
+ * Add conversions between ShortByteString and CString (#126)
+
 0.10.8.2 Duncan Coutts <duncan@community.haskell.org> Feb 2017
 
  * Make readFile work for files with no size like /dev/null
diff --git a/Data/ByteString.hs b/Data/ByteString.hs
--- a/Data/ByteString.hs
+++ b/Data/ByteString.hs
@@ -20,9 +20,9 @@
 -- Stability   : stable
 -- Portability : portable
 --
--- A time and space-efficient implementation of byte vectors using
+-- A time- and space-efficient implementation of byte vectors using
 -- packed Word8 arrays, suitable for high performance use, both in terms
--- of large data quantities, or high speed requirements. Byte vectors
+-- of large data quantities and high speed requirements. Byte vectors
 -- are encoded as strict 'Word8' arrays of bytes, held in a 'ForeignPtr',
 -- and can be passed between C and Haskell with little effort.
 --
@@ -322,8 +322,8 @@
 
 -- | /O(n)/ Convert a @['Word8']@ into a 'ByteString'.
 --
--- For applications with large numbers of string literals, pack can be a
--- bottleneck. In such cases, consider using packAddress (GHC only).
+-- For applications with large numbers of string literals, 'pack' can be a
+-- bottleneck. In such cases, consider using 'unsafePackAddress' (GHC only).
 pack :: [Word8] -> ByteString
 pack = packBytes
 
@@ -548,7 +548,7 @@
     | otherwise = foldl f (unsafeHead ps) (unsafeTail ps)
 {-# INLINE foldl1 #-}
 
--- | 'foldl1\'' is like 'foldl1', but strict in the accumulator.
+-- | 'foldl1'' is like 'foldl1', but strict in the accumulator.
 -- An exception will be thrown in the case of an empty ByteString.
 foldl1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
 foldl1' f ps
@@ -565,7 +565,7 @@
     | otherwise      = foldr f (unsafeLast ps) (unsafeInit ps)
 {-# INLINE foldr1 #-}
 
--- | 'foldr1\'' is a variant of 'foldr1', but is strict in the
+-- | 'foldr1'' is a variant of 'foldr1', but is strict in the
 -- accumulator.
 foldr1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
 foldr1' f ps
@@ -1413,7 +1413,7 @@
 
 {-# DEPRECATED findSubstring "findSubstring is deprecated in favour of breakSubstring." #-}
 
--- | Find the indexes of all (possibly overlapping) occurances of a
+-- | Find the indexes of all (possibly overlapping) occurences of a
 -- substring in a string.
 --
 findSubstrings :: ByteString -- ^ String to search for.
@@ -1771,7 +1771,7 @@
 -- | Read a handle's entire contents strictly into a 'ByteString'.
 --
 -- This function reads chunks at a time, increasing the chunk size on each
--- read. The final string is then realloced to the appropriate size. For
+-- read. The final string is then reallocated to the appropriate size. For
 -- files > half of available memory, this may lead to memory exhaustion.
 -- Consider using 'readFile' in this case.
 --
diff --git a/Data/ByteString/Builder/ASCII.hs b/Data/ByteString/Builder/ASCII.hs
--- a/Data/ByteString/Builder/ASCII.hs
+++ b/Data/ByteString/Builder/ASCII.hs
@@ -1,6 +1,6 @@
 {-# LANGUAGE ScopedTypeVariables, CPP, ForeignFunctionInterface,
              MagicHash, UnboxedTuples #-}
-{-# OPTIONS_HADDOCK hide #-}
+{-# OPTIONS_HADDOCK not-home #-}
 #if __GLASGOW_HASKELL__ >= 701
 {-# LANGUAGE Trustworthy #-}
 #endif
diff --git a/Data/ByteString/Builder/Internal.hs b/Data/ByteString/Builder/Internal.hs
--- a/Data/ByteString/Builder/Internal.hs
+++ b/Data/ByteString/Builder/Internal.hs
@@ -6,7 +6,7 @@
 #if __GLASGOW_HASKELL__ >= 703
 {-# LANGUAGE Unsafe #-}
 #endif
-{-# OPTIONS_HADDOCK hide #-}
+{-# OPTIONS_HADDOCK not-home #-}
 -- | Copyright : (c) 2010 - 2011 Simon Meier
 -- License     : BSD3-style (see LICENSE)
 --
@@ -134,7 +134,7 @@
 
 import           Control.Arrow (second)
 
-#if MIN_VERSION_base(4,9,0)
+#if !(MIN_VERSION_base(4,11,0)) && MIN_VERSION_base(4,9,0)
 import           Data.Semigroup (Semigroup((<>)))
 #endif
 #if !(MIN_VERSION_base(4,8,0))
@@ -968,7 +968,7 @@
 byteString = byteStringThreshold maximalCopySize
 
 -- | Create a 'Builder' denoting the same sequence of bytes as a lazy
--- 'S.ByteString'.
+-- 'L.ByteString'.
 -- The 'Builder' inserts large chunks of the lazy 'L.ByteString' directly,
 -- but copies small ones to ensure that the generated chunks are large on
 -- average.
diff --git a/Data/ByteString/Builder/Prim/Internal.hs b/Data/ByteString/Builder/Prim/Internal.hs
--- a/Data/ByteString/Builder/Prim/Internal.hs
+++ b/Data/ByteString/Builder/Prim/Internal.hs
@@ -2,7 +2,7 @@
 #if __GLASGOW_HASKELL__ >= 703
 {-# LANGUAGE Unsafe #-}
 #endif
-{-# OPTIONS_HADDOCK hide #-}
+{-# OPTIONS_HADDOCK not-home #-}
 -- |
 -- Copyright   : 2010-2011 Simon Meier, 2010 Jasper van der Jeugt
 -- License     : BSD3-style (see LICENSE)
@@ -272,7 +272,7 @@
 -- Unicode codepoints above 127 as follows.
 --
 -- @
---charASCIIDrop = 'condB' (< '\128') ('fromF' 'char7') 'emptyB'
+--charASCIIDrop = 'condB' (< \'\\128\') ('fromF' 'char7') 'emptyB'
 -- @
 {-# INLINE CONLIKE condB #-}
 condB :: (a -> Bool) -> BoundedPrim a -> BoundedPrim a -> BoundedPrim a
diff --git a/Data/ByteString/Builder/Prim/Internal/Floating.hs b/Data/ByteString/Builder/Prim/Internal/Floating.hs
--- a/Data/ByteString/Builder/Prim/Internal/Floating.hs
+++ b/Data/ByteString/Builder/Prim/Internal/Floating.hs
@@ -26,7 +26,7 @@
 import Data.ByteString.Builder.Prim.Internal
 
 {-
-We work around ticket http://hackage.haskell.org/trac/ghc/ticket/4092 using the
+We work around ticket http://ghc.haskell.org/trac/ghc/ticket/4092 using the
 FFI to store the Float/Double in the buffer and peek it out again from there.
 -}
 
diff --git a/Data/ByteString/Char8.hs b/Data/ByteString/Char8.hs
--- a/Data/ByteString/Char8.hs
+++ b/Data/ByteString/Char8.hs
@@ -66,7 +66,7 @@
         null,                   -- :: ByteString -> Bool
         length,                 -- :: ByteString -> Int
 
-        -- * Transformating ByteStrings
+        -- * Transforming ByteStrings
         map,                    -- :: (Char -> Char) -> ByteString -> ByteString
         reverse,                -- :: ByteString -> ByteString
         intersperse,            -- :: Char -> ByteString -> ByteString
@@ -348,7 +348,7 @@
 foldl f = B.foldl (\a c -> f a (w2c c))
 {-# INLINE foldl #-}
 
--- | 'foldl\'' is like foldl, but strict in the accumulator.
+-- | 'foldl'' is like foldl, but strict in the accumulator.
 foldl' :: (a -> Char -> a) -> a -> ByteString -> a
 foldl' f = B.foldl' (\a c -> f a (w2c c))
 {-# INLINE foldl' #-}
@@ -360,7 +360,7 @@
 foldr f = B.foldr (\c a -> f (w2c c) a)
 {-# INLINE foldr #-}
 
--- | 'foldr\'' is a strict variant of foldr
+-- | 'foldr'' is a strict variant of foldr
 foldr' :: (Char -> a -> a) -> a -> ByteString -> a
 foldr' f = B.foldr' (\c a -> f (w2c c) a)
 {-# INLINE foldr' #-}
@@ -897,6 +897,8 @@
 -- | readInt reads an Int from the beginning of the ByteString.  If there is no
 -- integer at the beginning of the string, it returns Nothing, otherwise
 -- it just returns the int read, and the rest of the string.
+--
+-- Note: This function will overflow the Int for large integers.
 readInt :: ByteString -> Maybe (Int, ByteString)
 readInt as
     | null as   = Nothing
diff --git a/Data/ByteString/Internal.hs b/Data/ByteString/Internal.hs
--- a/Data/ByteString/Internal.hs
+++ b/Data/ByteString/Internal.hs
@@ -4,7 +4,7 @@
 #if __GLASGOW_HASKELL__ >= 703
 {-# LANGUAGE Unsafe #-}
 #endif
-{-# OPTIONS_HADDOCK hide #-}
+{-# OPTIONS_HADDOCK not-home #-}
 
 -- |
 -- Module      : Data.ByteString.Internal
@@ -91,7 +91,7 @@
 
 import Foreign.C.String         (CString)
 
-#if MIN_VERSION_base(4,9,0)
+#if !(MIN_VERSION_base(4,11,0)) && MIN_VERSION_base(4,9,0)
 import Data.Semigroup           (Semigroup((<>)))
 #endif
 #if !(MIN_VERSION_base(4,8,0))
@@ -219,11 +219,11 @@
 -- | /O(n)/ Pack a null-terminated sequence of bytes, pointed to by an
 -- Addr\# (an arbitrary machine address assumed to point outside the
 -- garbage-collected heap) into a @ByteString@. A much faster way to
--- create an Addr\# is with an unboxed string literal, than to pack a
+-- create an 'Addr#' is with an unboxed string literal, than to pack a
 -- boxed string. A unboxed string literal is compiled to a static @char
 -- []@ by GHC. Establishing the length of the string requires a call to
--- @strlen(3)@, so the Addr# must point to a null-terminated buffer (as
--- is the case with "string"# literals in GHC). Use 'unsafePackAddressLen'
+-- @strlen(3)@, so the 'Addr#' must point to a null-terminated buffer (as
+-- is the case with @\"string\"\#@ literals in GHC). Use 'unsafePackAddressLen'
 -- if you know the length of the string statically.
 --
 -- An example:
@@ -231,10 +231,10 @@
 -- > literalFS = unsafePackAddress "literal"#
 --
 -- This function is /unsafe/. If you modify the buffer pointed to by the
--- original Addr# this modification will be reflected in the resulting
+-- original 'Addr#' this modification will be reflected in the resulting
 -- @ByteString@, breaking referential transparency.
 --
--- Note this also won't work if your Addr# has embedded '\0' characters in
+-- Note this also won't work if your 'Addr#' has embedded @\'\\0\'@ characters in
 -- the string, as @strlen@ will return too short a length.
 --
 unsafePackAddress :: Addr# -> IO ByteString
diff --git a/Data/ByteString/Lazy.hs b/Data/ByteString/Lazy.hs
--- a/Data/ByteString/Lazy.hs
+++ b/Data/ByteString/Lazy.hs
@@ -357,7 +357,7 @@
 cons c cs = Chunk (S.singleton c) cs
 {-# INLINE cons #-}
 
--- | /O(1)/ Unlike 'cons', 'cons\'' is
+-- | /O(1)/ Unlike 'cons', 'cons'' is
 -- strict in the ByteString that we are consing onto. More precisely, it forces
 -- the head and the first chunk. It does this because, for space efficiency, it
 -- may coalesce the new byte onto the first \'chunk\' rather than starting a
@@ -365,7 +365,7 @@
 --
 -- So that means you can't use a lazy recursive contruction like this:
 --
--- > let xs = cons\' c xs in xs
+-- > let xs = cons' c xs in xs
 --
 -- You can however use 'cons', as well as 'repeat' and 'cycle', to build
 -- infinite lazy ByteStrings.
@@ -488,7 +488,7 @@
         go a (Chunk c cs) = go (S.foldl f a c) cs
 {-# INLINE foldl #-}
 
--- | 'foldl\'' is like 'foldl', but strict in the accumulator.
+-- | 'foldl'' is like 'foldl', but strict in the accumulator.
 foldl' :: (a -> Word8 -> a) -> a -> ByteString -> a
 foldl' f z = go z
   where go !a Empty        = a
@@ -508,7 +508,7 @@
 foldl1 _ Empty        = errorEmptyList "foldl1"
 foldl1 f (Chunk c cs) = foldl f (S.unsafeHead c) (Chunk (S.unsafeTail c) cs)
 
--- | 'foldl1\'' is like 'foldl1', but strict in the accumulator.
+-- | 'foldl1'' is like 'foldl1', but strict in the accumulator.
 foldl1' :: (Word8 -> Word8 -> Word8) -> ByteString -> Word8
 foldl1' _ Empty        = errorEmptyList "foldl1'"
 foldl1' f (Chunk c cs) = foldl' f (S.unsafeHead c) (Chunk (S.unsafeTail c) cs)
diff --git a/Data/ByteString/Lazy/Char8.hs b/Data/ByteString/Lazy/Char8.hs
--- a/Data/ByteString/Lazy/Char8.hs
+++ b/Data/ByteString/Lazy/Char8.hs
@@ -251,7 +251,7 @@
 cons = L.cons . c2w
 {-# INLINE cons #-}
 
--- | /O(1)/ Unlike 'cons', 'cons\'' is
+-- | /O(1)/ Unlike 'cons', 'cons'' is
 -- strict in the ByteString that we are consing onto. More precisely, it forces
 -- the head and the first chunk. It does this because, for space efficiency, it
 -- may coalesce the new byte onto the first \'chunk\' rather than starting a
@@ -259,7 +259,7 @@
 --
 -- So that means you can't use a lazy recursive contruction like this:
 --
--- > let xs = cons\' c xs in xs
+-- > let xs = cons' c xs in xs
 --
 -- You can however use 'cons', as well as 'repeat' and 'cycle', to build
 -- infinite lazy ByteStrings.
@@ -319,7 +319,7 @@
 foldl f = L.foldl (\a c -> f a (w2c c))
 {-# INLINE foldl #-}
 
--- | 'foldl\'' is like foldl, but strict in the accumulator.
+-- | 'foldl'' is like foldl, but strict in the accumulator.
 foldl' :: (a -> Char -> a) -> a -> ByteString -> a
 foldl' f = L.foldl' (\a c -> f a (w2c c))
 {-# INLINE foldl' #-}
@@ -337,7 +337,7 @@
 foldl1 f ps = w2c (L.foldl1 (\x y -> c2w (f (w2c x) (w2c y))) ps)
 {-# INLINE foldl1 #-}
 
--- | 'foldl1\'' is like 'foldl1', but strict in the accumulator.
+-- | 'foldl1'' is like 'foldl1', but strict in the accumulator.
 foldl1' :: (Char -> Char -> Char) -> ByteString -> Char
 foldl1' f ps = w2c (L.foldl1' (\x y -> c2w (f (w2c x) (w2c y))) ps)
 
@@ -756,6 +756,8 @@
 -- there is no integer at the beginning of the string, it returns
 -- Nothing, otherwise it just returns the int read, and the rest of the
 -- string.
+--
+-- Note: This function will overflow the Int for large integers.
 
 readInt :: ByteString -> Maybe (Int, ByteString)
 {-# INLINE readInt #-}
diff --git a/Data/ByteString/Lazy/Internal.hs b/Data/ByteString/Lazy/Internal.hs
--- a/Data/ByteString/Lazy/Internal.hs
+++ b/Data/ByteString/Lazy/Internal.hs
@@ -3,7 +3,7 @@
 #if __GLASGOW_HASKELL__ >= 703
 {-# LANGUAGE Unsafe #-}
 #endif
-{-# OPTIONS_HADDOCK hide #-}
+{-# OPTIONS_HADDOCK not-home #-}
 
 -- |
 -- Module      : Data.ByteString.Lazy.Internal
@@ -51,7 +51,7 @@
 import Data.Word        (Word8)
 import Foreign.Storable (Storable(sizeOf))
 
-#if MIN_VERSION_base(4,9,0)
+#if !(MIN_VERSION_base(4,11,0)) && MIN_VERSION_base(4,9,0)
 import Data.Semigroup   (Semigroup((<>)))
 #endif
 #if !(MIN_VERSION_base(4,8,0))
diff --git a/Data/ByteString/Short.hs b/Data/ByteString/Short.hs
--- a/Data/ByteString/Short.hs
+++ b/Data/ByteString/Short.hs
@@ -78,6 +78,15 @@
 
     -- * Other operations
     empty, null, length, index,
+
+    -- * Low level conversions
+    -- ** Packing 'CString's and pointers
+    packCString,
+    packCStringLen,
+
+    -- ** Using ByteStrings as 'CString's
+    useAsCString,
+    useAsCStringLen
   ) where
 
 import Data.ByteString.Short.Internal
diff --git a/Data/ByteString/Short/Internal.hs b/Data/ByteString/Short/Internal.hs
--- a/Data/ByteString/Short/Internal.hs
+++ b/Data/ByteString/Short/Internal.hs
@@ -5,7 +5,7 @@
 #if __GLASGOW_HASKELL__ >= 703
 {-# LANGUAGE Unsafe #-}
 #endif
-{-# OPTIONS_HADDOCK hide #-}
+{-# OPTIONS_HADDOCK not-home #-}
 
 -- |
 -- Module      : Data.ByteString.Short.Internal
@@ -33,10 +33,19 @@
     empty, null, length, index, unsafeIndex,
 
     -- * Low level operations
-    createFromPtr, copyToPtr
+    createFromPtr, copyToPtr,
+
+    -- * Low level conversions
+    -- ** Packing 'CString's and pointers
+    packCString,
+    packCStringLen,
+
+    -- ** Using ByteStrings as 'CString's
+    useAsCString,
+    useAsCStringLen
   ) where
 
-import Data.ByteString.Internal (ByteString(..), accursedUnutterablePerformIO)
+import Data.ByteString.Internal (ByteString(..), accursedUnutterablePerformIO, c_strlen)
 
 import Data.Typeable    (Typeable)
 import Data.Data        (Data(..), mkNoRepType)
@@ -47,6 +56,7 @@
 import Data.String      (IsString(..))
 import Control.DeepSeq  (NFData(..))
 import qualified Data.List as List (length)
+import Foreign.C.String (CString, CStringLen)
 #if MIN_VERSION_base(4,7,0)
 import Foreign.C.Types  (CSize(..), CInt(..))
 #elif MIN_VERSION_base(4,4,0)
@@ -54,6 +64,7 @@
 #else
 import Foreign.C.Types  (CSize, CInt, CLong)
 #endif
+import Foreign.Marshal.Alloc (allocaBytes)
 import Foreign.Ptr
 import Foreign.ForeignPtr (touchForeignPtr)
 #if MIN_VERSION_base(4,5,0)
@@ -61,6 +72,7 @@
 #else
 import Foreign.ForeignPtr (unsafeForeignPtrToPtr)
 #endif
+import Foreign.Storable (pokeByteOff)
 
 #if MIN_VERSION_base(4,5,0)
 import qualified GHC.Exts
@@ -90,7 +102,8 @@
 import GHC.Word
 
 import Prelude ( Eq(..), Ord(..), Ordering(..), Read(..), Show(..)
-               , ($), error, (++)
+               , ($), error, (++), (.)
+               , String, userError
                , Bool(..), (&&), otherwise
                , (+), (-), fromIntegral
                , return )
@@ -595,3 +608,60 @@
                    -> ByteArray# -> CLong -> CSize -> IO ()
 #endif
 
+-- | /O(n)./ Construct a new @ShortByteString@ from a @CString@. The
+-- resulting @ShortByteString@ is an immutable copy of the original
+-- @CString@, and is managed on the Haskell heap. The original
+-- @CString@ must be null terminated.
+--
+-- @since 0.10.10.0
+packCString :: CString -> IO ShortByteString
+packCString cstr = do
+  len <- c_strlen cstr
+  packCStringLen (cstr, fromIntegral len)
+
+-- | /O(n)./ Construct a new @ShortByteString@ from a @CStringLen@. The
+-- resulting @ShortByteString@ is an immutable copy of the original @CStringLen@.
+-- The @ShortByteString@ is a normal Haskell value and will be managed on the
+-- Haskell heap.
+--
+-- @since 0.10.10.0
+packCStringLen :: CStringLen -> IO ShortByteString
+packCStringLen (cstr, len) | len >= 0 = createFromPtr cstr len
+packCStringLen (_, len) =
+  moduleErrorIO "packCStringLen" ("negative length: " ++ show len)
+
+-- | /O(n) construction./ Use a @ShortByteString@ with a function requiring a
+-- null-terminated @CString@.  The @CString@ is a copy and will be freed
+-- automatically; it must not be stored or used after the
+-- subcomputation finishes.
+--
+-- @since 0.10.10.0
+useAsCString :: ShortByteString -> (CString -> IO a) -> IO a
+useAsCString bs action =
+  allocaBytes (l+1) $ \buf -> do
+      copyToPtr bs 0 buf (fromIntegral l)
+      pokeByteOff buf l (0::Word8)
+      action buf
+  where l = length bs
+
+-- | /O(n) construction./ Use a @ShortByteString@ with a function requiring a @CStringLen@.
+-- As for @useAsCString@ this function makes a copy of the original @ShortByteString@.
+-- It must not be stored or used after the subcomputation finishes.
+--
+-- @since 0.10.10.0
+useAsCStringLen :: ShortByteString -> (CStringLen -> IO a) -> IO a
+useAsCStringLen bs action =
+  allocaBytes l $ \buf -> do
+      copyToPtr bs 0 buf (fromIntegral l)
+      action (buf, l)
+  where l = length bs
+
+-- ---------------------------------------------------------------------
+-- Internal utilities
+
+moduleErrorIO :: String -> String -> IO a
+moduleErrorIO fun msg = throwIO . userError $ moduleErrorMsg fun msg
+{-# NOINLINE moduleErrorIO #-}
+
+moduleErrorMsg :: String -> String -> String
+moduleErrorMsg fun msg = "Data.ByteString.Short." ++ fun ++ ':':' ':msg
diff --git a/Data/ByteString/Unsafe.hs b/Data/ByteString/Unsafe.hs
--- a/Data/ByteString/Unsafe.hs
+++ b/Data/ByteString/Unsafe.hs
@@ -125,7 +125,7 @@
 
 -- | /O(1)/ 'unsafePackAddressLen' provides constant-time construction of
 -- 'ByteString's, which is ideal for string literals. It packs a sequence
--- of bytes into a @ByteString@, given a raw 'Addr#' to the string, and
+-- of bytes into a 'ByteString', given a raw 'Addr#' to the string, and
 -- the length of the string.
 --
 -- This function is /unsafe/ in two ways:
@@ -134,8 +134,8 @@
 -- argument is incorrect, it is possible to overstep the end of the
 -- byte array.
 --
--- * if the underying Addr# is later modified, this change will be
--- reflected in resulting @ByteString@, breaking referential
+-- * if the underlying 'Addr#' is later modified, this change will be
+-- reflected in the resulting 'ByteString', breaking referential
 -- transparency.
 --
 -- If in doubt, don't use this function.
@@ -153,7 +153,7 @@
 -- This function is /unsafe/, it is possible to break referential
 -- transparency by modifying the underlying buffer pointed to by the
 -- first argument. Any changes to the original buffer will be reflected
--- in the resulting @ByteString@.
+-- in the resulting 'ByteString'.
 --
 unsafePackCStringFinalizer :: Ptr Word8 -> Int -> IO () -> IO ByteString
 unsafePackCStringFinalizer p l f = do
@@ -165,7 +165,7 @@
 -- references.
 --
 -- This function is /unsafe/, as there may be other
--- 'ByteStrings' referring to the same underlying pages. If you use
+-- 'ByteString's referring to the same underlying pages. If you use
 -- this, you need to have a proof of some kind that all 'ByteString's
 -- ever generated from the underlying byte array are no longer live.
 --
@@ -175,13 +175,13 @@
 ------------------------------------------------------------------------
 -- Packing CStrings into ByteStrings
 
--- | /O(n)/ Build a @ByteString@ from a @CString@. This value will have /no/
+-- | /O(n)/ Build a 'ByteString' from a 'CString'. This value will have /no/
 -- finalizer associated to it, and will not be garbage collected by
 -- Haskell. The ByteString length is calculated using /strlen(3)/,
 -- and thus the complexity is a /O(n)/.
 --
--- This function is /unsafe/. If the @CString@ is later modified, this
--- change will be reflected in the resulting @ByteString@, breaking
+-- This function is /unsafe/. If the 'CString' is later modified, this
+-- change will be reflected in the resulting 'ByteString', breaking
 -- referential transparency.
 --
 unsafePackCString :: CString -> IO ByteString
@@ -190,13 +190,13 @@
     l <- c_strlen cstr
     return $! PS fp 0 (fromIntegral l)
 
--- | /O(1)/ Build a @ByteString@ from a @CStringLen@. This value will
+-- | /O(1)/ Build a 'ByteString' from a 'CStringLen'. This value will
 -- have /no/ finalizer associated with it, and will not be garbage
 -- collected by Haskell. This operation has /O(1)/ complexity as we
 -- already know the final size, so no /strlen(3)/ is required.
 --
--- This function is /unsafe/. If the original @CStringLen@ is later
--- modified, this change will be reflected in the resulting @ByteString@,
+-- This function is /unsafe/. If the original 'CStringLen' is later
+-- modified, this change will be reflected in the resulting 'ByteString',
 -- breaking referential transparency.
 --
 unsafePackCStringLen :: CStringLen -> IO ByteString
@@ -204,16 +204,16 @@
     fp <- newForeignPtr_ (castPtr ptr)
     return $! PS fp 0 (fromIntegral len)
 
--- | /O(n)/ Build a @ByteString@ from a malloced @CString@. This value will
+-- | /O(n)/ Build a 'ByteString' from a malloced 'CString'. This value will
 -- have a @free(3)@ finalizer associated to it.
 --
--- This function is /unsafe/. If the original @CString@ is later
--- modified, this change will be reflected in the resulting @ByteString@,
+-- This function is /unsafe/. If the original 'CString' is later
+-- modified, this change will be reflected in the resulting 'ByteString',
 -- breaking referential transparency.
 --
 -- This function is also unsafe if you call its finalizer twice,
 -- which will result in a /double free/ error, or if you pass it
--- a CString not allocated with 'malloc'.
+-- a 'CString' not allocated with 'malloc'.
 --
 unsafePackMallocCString :: CString -> IO ByteString
 unsafePackMallocCString cstr = do
@@ -221,16 +221,16 @@
     len <- c_strlen cstr
     return $! PS fp 0 (fromIntegral len)
 
--- | /O(1)/ Build a @ByteString@ from a malloced @CStringLen@. This
+-- | /O(1)/ Build a 'ByteString' from a malloced 'CStringLen'. This
 -- value will have a @free(3)@ finalizer associated to it.
 --
--- This function is /unsafe/. If the original @CString@ is later
--- modified, this change will be reflected in the resulting @ByteString@,
+-- This function is /unsafe/. If the original 'CString' is later
+-- modified, this change will be reflected in the resulting 'ByteString',
 -- breaking referential transparency.
 --
 -- This function is also unsafe if you call its finalizer twice,
 -- which will result in a /double free/ error, or if you pass it
--- a CString not allocated with 'malloc'.
+-- a 'CString' not allocated with 'malloc'.
 --
 unsafePackMallocCStringLen :: CStringLen -> IO ByteString
 unsafePackMallocCStringLen (cstr, len) = do
@@ -239,26 +239,26 @@
 
 -- ---------------------------------------------------------------------
 
--- | /O(1) construction/ Use a @ByteString@ with a function requiring a
--- @CString@.
+-- | /O(1) construction/ Use a 'ByteString' with a function requiring a
+-- 'CString'.
 --
--- This function does zero copying, and merely unwraps a @ByteString@ to
--- appear as a @CString@. It is /unsafe/ in two ways:
+-- This function does zero copying, and merely unwraps a 'ByteString' to
+-- appear as a 'CString'. It is /unsafe/ in two ways:
 --
--- * After calling this function the @CString@ shares the underlying
--- byte buffer with the original @ByteString@. Thus modifying the
--- @CString@, either in C, or using poke, will cause the contents of the
--- @ByteString@ to change, breaking referential transparency. Other
--- @ByteStrings@ created by sharing (such as those produced via 'take'
--- or 'drop') will also reflect these changes. Modifying the @CString@
+-- * After calling this function the 'CString' shares the underlying
+-- byte buffer with the original 'ByteString'. Thus modifying the
+-- 'CString', either in C, or using poke, will cause the contents of the
+-- 'ByteString' to change, breaking referential transparency. Other
+-- 'ByteString's created by sharing (such as those produced via 'take'
+-- or 'drop') will also reflect these changes. Modifying the 'CString'
 -- will break referential transparency. To avoid this, use
--- @useAsCString@, which makes a copy of the original @ByteString@.
+-- 'useAsCString', which makes a copy of the original 'ByteString'.
 --
--- * @CStrings@ are often passed to functions that require them to be
--- null-terminated. If the original @ByteString@ wasn't null terminated,
--- neither will the @CString@ be. It is the programmers responsibility
--- to guarantee that the @ByteString@ is indeed null terminated. If in
--- doubt, use @useAsCString@.
+-- * 'CString's are often passed to functions that require them to be
+-- null-terminated. If the original 'ByteString' wasn't null terminated,
+-- neither will the 'CString' be. It is the programmers responsibility
+-- to guarantee that the 'ByteString' is indeed null terminated. If in
+-- doubt, use 'useAsCString'.
 --
 -- * The memory may freed at any point after the subcomputation
 -- terminates, so the pointer to the storage must *not* be used
@@ -267,20 +267,20 @@
 unsafeUseAsCString :: ByteString -> (CString -> IO a) -> IO a
 unsafeUseAsCString (PS ps s _) ac = withForeignPtr ps $ \p -> ac (castPtr p `plusPtr` s)
 
--- | /O(1) construction/ Use a @ByteString@ with a function requiring a
--- @CStringLen@.
+-- | /O(1) construction/ Use a 'ByteString' with a function requiring a
+-- 'CStringLen'.
 --
--- This function does zero copying, and merely unwraps a @ByteString@ to
--- appear as a @CStringLen@. It is /unsafe/:
+-- This function does zero copying, and merely unwraps a 'ByteString' to
+-- appear as a 'CStringLen'. It is /unsafe/:
 --
--- * After calling this function the @CStringLen@ shares the underlying
--- byte buffer with the original @ByteString@. Thus modifying the
--- @CStringLen@, either in C, or using poke, will cause the contents of the
--- @ByteString@ to change, breaking referential transparency. Other
--- @ByteStrings@ created by sharing (such as those produced via 'take'
--- or 'drop') will also reflect these changes. Modifying the @CStringLen@
+-- * After calling this function the 'CStringLen' shares the underlying
+-- byte buffer with the original 'ByteString'. Thus modifying the
+-- 'CStringLen', either in C, or using poke, will cause the contents of the
+-- 'ByteString' to change, breaking referential transparency. Other
+-- 'ByteString's created by sharing (such as those produced via 'take'
+-- or 'drop') will also reflect these changes. Modifying the 'CStringLen'
 -- will break referential transparency. To avoid this, use
--- @useAsCStringLen@, which makes a copy of the original @ByteString@.
+-- 'useAsCStringLen', which makes a copy of the original 'ByteString'.
 --
 unsafeUseAsCStringLen :: ByteString -> (CStringLen -> IO a) -> IO a
 unsafeUseAsCStringLen (PS ps s l) f = withForeignPtr ps $ \p -> f (castPtr p `plusPtr` s,l)
diff --git a/bytestring.cabal b/bytestring.cabal
--- a/bytestring.cabal
+++ b/bytestring.cabal
@@ -1,5 +1,5 @@
 Name:                bytestring
-Version:             0.10.8.2
+Version:             0.10.9.0
 Synopsis:            Fast, compact, strict and lazy byte strings with a list interface
 Description:
     An efficient compact, immutable byte string type (both strict and lazy)
@@ -153,7 +153,7 @@
   hs-source-dirs:   . tests
   build-depends:    base, ghc-prim, deepseq, random, directory,
                     test-framework, test-framework-quickcheck2,
-                    QuickCheck >= 2.3
+                    QuickCheck >= 2.10 && < 2.14
   c-sources:        cbits/fpstring.c
   include-dirs:     include
   ghc-options:      -fwarn-unused-binds
@@ -198,7 +198,7 @@
 
   build-depends:    base, ghc-prim,
                     deepseq,
-                    QuickCheck                 >= 2.4,
+                    QuickCheck                 >= 2.10 && < 2.14,
                     byteorder                  == 1.0.*,
                     dlist                      >= 0.5 && < 0.9,
                     directory,
diff --git a/tests/Properties.hs b/tests/Properties.hs
--- a/tests/Properties.hs
+++ b/tests/Properties.hs
@@ -295,21 +295,23 @@
      ) :: Int -> B)
 
 
-prop_iterateLC =
-  forAll arbitrarySizedIntegral $
+prop_iterateLC :: Int -> (Char8 -> Char8) -> Char8 -> Bool
+prop_iterateLC n f (Char8 c) =
   eq3
-    ((\n f a -> LC.take (fromIntegral n) $
-        LC.iterate  f a) :: Int -> (Char -> Char) -> Char -> B)
-    ((\n f a -> fst $
-        C.unfoldrN n (\a -> Just (f a, f a)) a) :: Int -> (Char -> Char) -> Char -> P)
+    (\n f a -> LC.take (fromIntegral n) $ LC.iterate  f a)
+    (\n f a -> fst $ C.unfoldrN n (\a -> Just (f a, f a)) a)
+    n
+    (castFn f :: Char -> Char)
+    c
 
-prop_iterateLC_2   =
-  forAll arbitrarySizedIntegral $
+prop_iterateLC_2 :: Int -> (Char8 -> Char8) -> Char8 -> Bool
+prop_iterateLC_2 n f (Char8 c) =
   eq3
-    ((\n f a -> LC.take (fromIntegral n) $
-        LC.iterate  f a) :: Int -> (Char -> Char) -> Char -> B)
-    ((\n f a -> LC.take (fromIntegral n) $
-        LC.unfoldr (\a -> Just (f a, f a)) a) :: Int -> (Char -> Char) -> Char -> B)
+    (\n f a -> LC.take (fromIntegral (n :: Int)) $ LC.iterate f a)
+    (\n f a -> LC.take (fromIntegral (n :: Int)) $ LC.unfoldr (\a -> Just (f a, f a)) a)
+    n
+    (castFn f :: Char -> Char)
+    c
 
 prop_iterateL   =
   forAll arbitrarySizedIntegral $
@@ -413,13 +415,17 @@
     (L.mapAccumR :: (X -> W -> (X,W)) -> X -> B   -> (X, B))
     (  mapAccumR :: (X -> W -> (X,W)) -> X -> [W] -> (X, [W]))
 
-prop_mapAccumRDL  = eq3
+prop_mapAccumRDL :: (X -> Char8 -> (X, Char8)) -> X -> B -> Bool
+prop_mapAccumRDL f = eq3
     (D.mapAccumR :: (X -> Char -> (X,Char)) -> X -> B   -> (X, B))
     (  mapAccumR :: (X -> Char -> (X,Char)) -> X -> [Char] -> (X, [Char]))
+    (castFn f)
 
-prop_mapAccumRCC  = eq3
+prop_mapAccumRCC :: (X -> Char8 -> (X, Char8)) -> X -> P -> Bool
+prop_mapAccumRCC f = eq3
     (C.mapAccumR :: (X -> Char -> (X,Char)) -> X -> P   -> (X, P))
     (  mapAccumR :: (X -> Char -> (X,Char)) -> X -> [Char] -> (X, [Char]))
+    (castFn f)
 
 prop_unfoldrBL =
   forAll arbitrarySizedIntegral $
@@ -490,8 +496,11 @@
 prop_zipLL        = L.zip        `eq2`   (zip :: [W] -> [W] -> [(W,W)])
 prop_unzipPL      = P.unzip      `eq1`   (unzip :: [(W,W)] -> ([W],[W]))
 prop_unzipLL      = L.unzip      `eq1`   (unzip :: [(W,W)] -> ([W],[W]))
-prop_unzipCL      = C.unzip      `eq1`   (unzip :: [(Char,Char)] -> ([Char],[Char]))
 
+prop_unzipCL :: [(Char8, Char8)] -> Bool
+prop_unzipCL xs   = (C.unzip     `eq1`   (unzip :: [(Char,Char)] -> ([Char],[Char])))
+                    [ (a,b) | (Char8 a, Char8 b) <- xs ]
+
 prop_foldl1PL     = P.foldl1    `eqnotnull2` (foldl1   :: (W -> W -> W) -> [W] -> W)
 prop_foldl1PL'    = P.foldl1'   `eqnotnull2` (foldl1' :: (W -> W -> W) -> [W] -> W)
 prop_foldr1PL     = P.foldr1    `eqnotnull2` (foldr1 :: (W -> W -> W) -> [W] -> W)
@@ -506,10 +515,26 @@
 prop_minimumPL    = P.minimum   `eqnotnull1` (minimum   :: [W] -> W)
 prop_tailPL       = P.tail      `eqnotnull1` (tail      :: [W] -> [W])
 
-prop_scanl1CL     = C.scanl1    `eqnotnull2` (scanl1 :: (Char -> Char -> Char) -> [Char] -> [Char])
-prop_scanrCL      = C.scanr     `eqnotnull3` (scanr  :: (Char -> Char -> Char) -> Char -> [Char] -> [Char])
-prop_scanr1CL     = C.scanr1    `eqnotnull2` (scanr1 :: (Char -> Char -> Char) -> [Char] -> [Char])
+prop_scanl1CL :: (Char8 -> Char8 -> Char8) -> P -> Property
+prop_scanrCL  :: (Char8 -> Char8 -> Char8) -> Char8 -> P -> Property
+prop_scanr1CL :: (Char8 -> Char8 -> Char8) -> P -> Property
 
+prop_scanl1CL f = eqnotnull2
+    C.scanl1
+    (scanl1 :: (Char -> Char -> Char) -> [Char] -> [Char])
+    (castFn f)
+
+prop_scanrCL f (Char8 c) = eqnotnull3
+    C.scanr
+    (scanr  :: (Char -> Char -> Char) -> Char -> [Char] -> [Char])
+    (castFn f)
+    c
+
+prop_scanr1CL f = eqnotnull2
+    C.scanr1
+    (scanr1 :: (Char -> Char -> Char) -> [Char] -> [Char])
+    (castFn f)
+
 -- prop_zipWithPL'   = P.zipWith'  `eq3` (zipWith :: (W -> W -> W) -> [W] -> [W] -> [W])
 
 prop_zipWithPL    = (P.zipWith  :: (W -> W -> X) -> P   -> P   -> [X]) `eq3`
@@ -578,7 +603,8 @@
 prop_compare7 x  y  = x  `compare` y  == (L.singleton x `compare` L.singleton y)
 prop_compare8 xs ys = xs `compare` ys == (L.pack xs `compare` L.pack ys)
 
-prop_compare7LL x  y  = x  `compare` y  == (LC.singleton x `compare` LC.singleton y)
+prop_compare7LL (Char8 x) (Char8 y) =
+                      x  `compare` y  == (LC.singleton x `compare` LC.singleton y)
 
 prop_empty1 = L.length L.empty == 0
 prop_empty2 = L.unpack L.empty == []
@@ -730,8 +756,14 @@
 
 prop_group xs       = group xs == (map unpack . L.group . pack) xs
 prop_groupBy  f xs  = groupBy f xs == (map unpack . L.groupBy f . pack) xs
-prop_groupBy_LC  f xs  = groupBy f xs == (map LC.unpack . LC.groupBy f .  LC.pack) xs
 
+prop_groupBy_LC :: (Char8 -> Char8 -> Bool) -> String8 -> Bool
+prop_groupBy_LC f' (String8 xs) =
+    groupBy f xs == (map LC.unpack . LC.groupBy f .  LC.pack) xs
+  where
+    f :: Char -> Char -> Bool
+    f = castFn f'
+
 -- prop_joinjoinByte xs ys c = L.joinWithByte c xs ys == L.join (L.singleton c) [xs,ys]
 
 prop_index xs =
@@ -739,19 +771,22 @@
     forAll indices $ \i -> (xs !! i) == L.pack xs `L.index` (fromIntegral i)
   where indices = choose (0, length xs -1)
 
-prop_index_D xs =
+prop_index_D (String8 xs) =
   not (null xs) ==>
     forAll indices $ \i -> (xs !! i) == D.pack xs `D.index` (fromIntegral i)
   where indices = choose (0, length xs -1)
 
-prop_index_C xs =
+prop_index_C (String8 xs) =
   not (null xs) ==>
     forAll indices $ \i -> (xs !! i) == C.pack xs `C.index` (fromIntegral i)
   where indices = choose (0, length xs -1)
 
 prop_elemIndex xs c = (elemIndex c xs) == fmap fromIntegral (L.elemIndex c (pack xs))
-prop_elemIndexCL xs c = (elemIndex c xs) == (C.elemIndex c (C.pack xs))
 
+prop_elemIndexCL :: String8 -> Char8 -> Bool
+prop_elemIndexCL (String8 xs) (Char8 c) =
+    (elemIndex c xs) == (C.elemIndex c (C.pack xs))
+
 prop_elemIndices xs c = elemIndices c xs == map fromIntegral (L.elemIndices c (pack xs))
 
 prop_count c xs = length (L.elemIndices c xs) == fromIntegral (L.count c xs)
@@ -865,14 +900,14 @@
 
 prop_breakspan_1BB xs c = P.break (== c) xs == P.span (/= c) xs
 
-prop_linesSBB xs = C.lines (C.pack xs) == map C.pack (lines xs)
+prop_linesSBB (String8 xs) = C.lines (C.pack xs) == map C.pack (lines xs)
 
 prop_unlinesSBB xss = C.unlines (map C.pack xss) == C.pack (unlines xss)
 
-prop_wordsSBB xs =
+prop_wordsSBB (String8 xs) =
     C.words (C.pack xs) == map C.pack (words xs)
 
-prop_wordsLC xs =
+prop_wordsLC (String8 xs) =
     LC.words (LC.pack xs) == map LC.pack (words xs)
 
 prop_unwordsSBB xss = C.unwords (map C.pack xss) == C.pack (unwords xss)
@@ -906,8 +941,8 @@
 
 prop_splitsplitWithBB c xs = P.split c xs == P.splitWith (== c) xs
 
-prop_bijectionBB  c = (P.w2c . P.c2w) c == id c
-prop_bijectionBB' w = (P.c2w . P.w2c) w == id w
+prop_bijectionBB  (Char8 c) = (P.w2c . P.c2w) c == id c
+prop_bijectionBB'        w  = (P.c2w . P.w2c) w == id w
 
 prop_packunpackBB  s = (P.unpack . P.pack) s == id s
 prop_packunpackBB' s = (P.pack . P.unpack) s == id s
@@ -924,13 +959,16 @@
 prop_compare5BB xs  = (not (null xs)) ==> (P.empty `compare` P.pack xs) == LT
 prop_compare6BB xs ys= (not (null ys)) ==> (P.pack (xs++ys)  `compare` P.pack xs) == GT
 
-prop_compare7BB x  y = x `compare` y == (C.singleton x `compare` C.singleton y)
+prop_compare7BB (Char8 x) (Char8 y) =
+                        x  `compare` y  == (C.singleton x `compare` C.singleton y)
 prop_compare8BB xs ys = xs `compare` ys == (P.pack xs `compare` P.pack ys)
 
 prop_consBB  c xs = P.unpack (P.cons c (P.pack xs)) == (c:xs)
-prop_cons1BB xs   = 'X' : xs == C.unpack ('X' `C.cons` (C.pack xs))
+prop_cons1BB (String8 xs)
+                  = 'X' : xs == C.unpack ('X' `C.cons` (C.pack xs))
 prop_cons2BB xs c = c : xs == P.unpack (c `P.cons` (P.pack xs))
-prop_cons3BB c    = C.unpack (C.singleton c) == (c:[])
+prop_cons3BB (Char8 c)
+                  = C.unpack (C.singleton c) == (c:[])
 prop_cons4BB c    = (c `P.cons` P.empty)  == P.pack (c:[])
 
 prop_snoc1BB xs c = xs ++ [c] == P.unpack ((P.pack xs) `P.snoc` c)
@@ -971,8 +1009,8 @@
 prop_map3BB f xs   = map f xs == (P.unpack . P.map f .  P.pack) xs
 -- prop_mapBB' f xs   = P.map' f (P.pack xs) == P.pack (map f xs)
 
-prop_filter1BB xs   = (filter (=='X') xs) == (C.unpack $ C.filter (=='X') (C.pack xs))
-prop_filter2BB p xs = (filter p xs) == (P.unpack $ P.filter p (P.pack xs))
+prop_filter1BB (String8 xs) = (filter (=='X') xs) == (C.unpack $ C.filter (=='X') (C.pack xs))
+prop_filter2BB p        xs  = (filter p       xs) == (P.unpack $ P.filter p (P.pack xs))
 
 prop_findBB p xs = find p xs == P.find p (P.pack xs)
 
@@ -1021,7 +1059,7 @@
 
 prop_dropWhileBB xs a = (dropWhile (/= a) xs) == (P.unpack . (P.dropWhile (/= a)) . P.pack) xs
 
-prop_dropWhileCC_isSpace xs =
+prop_dropWhileCC_isSpace (String8 xs) =
         (dropWhile isSpace xs) ==
        (C.unpack .  (C.dropWhile isSpace) . C.pack) xs
 
@@ -1065,30 +1103,34 @@
 prop_anyBB xs a = (any (== a) xs) == (P.any (== a) (P.pack xs))
 prop_allBB xs a = (all (== a) xs) == (P.all (== a) (P.pack xs))
 
-prop_linesBB xs = (lines xs) == ((map C.unpack) . C.lines . C.pack) xs
+prop_linesBB (String8 xs) =
+    (lines xs) == ((map C.unpack) . C.lines . C.pack) xs
 
-prop_unlinesBB xs = (unlines.lines) xs == (C.unpack. C.unlines . C.lines .C.pack) xs
-prop_unlinesLC xs = (unlines.lines) xs == (LC.unpack. LC.unlines .  LC.lines .LC.pack) xs
+prop_unlinesBB (String8 xs) =
+    (unlines.lines) xs == (C.unpack. C.unlines . C.lines .C.pack) xs
+prop_unlinesLC (String8 xs) =
+    (unlines.lines) xs == (LC.unpack. LC.unlines .  LC.lines .LC.pack) xs
 
-prop_wordsBB xs =
+prop_wordsBB (String8 xs) =
     (words xs) == ((map C.unpack) . C.words . C.pack) xs
 -- prop_wordstokensBB xs = C.words xs == C.tokens isSpace xs
 
-prop_unwordsBB xs =
+prop_unwordsBB (String8 xs) =
     (C.pack.unwords.words) xs == (C.unwords . C.words .C.pack) xs
 
 prop_groupBB xs   = group xs == (map P.unpack . P.group . P.pack) xs
 
 prop_groupByBB  xs = groupBy (==) xs == (map P.unpack . P.groupBy (==) . P.pack) xs
-prop_groupBy1CC xs = groupBy (==) xs == (map C.unpack . C.groupBy (==) . C.pack) xs
 prop_groupBy1BB xs = groupBy (/=) xs == (map P.unpack . P.groupBy (/=) . P.pack) xs
-prop_groupBy2CC xs = groupBy (/=) xs == (map C.unpack . C.groupBy (/=) . C.pack) xs
+prop_groupBy1CC (String8 xs) = groupBy (==) xs == (map C.unpack . C.groupBy (==) . C.pack) xs
+prop_groupBy2CC (String8 xs) = groupBy (/=) xs == (map C.unpack . C.groupBy (/=) . C.pack) xs
 
-prop_joinBB xs ys = (concat . (intersperse ys) . lines) xs ==
-               (C.unpack $ C.intercalate (C.pack ys) (C.lines (C.pack xs)))
+prop_joinBB (String8 xs) (String8 ys) =
+    (concat . (intersperse ys) . lines) xs ==
+    (C.unpack $ C.intercalate (C.pack ys) (C.lines (C.pack xs)))
 
-prop_elemIndex1BB xs   = (elemIndex 'X' xs) == (C.elemIndex 'X' (C.pack xs))
-prop_elemIndex2BB xs c = (elemIndex c xs) == (C.elemIndex c (C.pack xs))
+prop_elemIndex1BB (String8 xs)           = (elemIndex 'X' xs) == (C.elemIndex 'X' (C.pack xs))
+prop_elemIndex2BB (String8 xs) (Char8 c) = (elemIndex  c  xs) == (C.elemIndex  c  (C.pack xs))
 
 -- prop_lineIndices1BB xs = C.elemIndices '\n' xs == C.lineIndices xs
 
@@ -1253,14 +1295,14 @@
 prop_readBB x = (read . show) x == (x :: P.ByteString)
 prop_readLL x = (read . show) x == (x :: L.ByteString)
 
-prop_readint2BB s =
+prop_readint2BB (String8 s) =
     let s' = filter (\c -> c `notElem` ['0'..'9']) s
     in C.readInt (C.pack s') == Nothing
 
 prop_readintegerBB n = (fst . fromJust . C.readInteger . C.pack . show) n == (n :: Integer)
 prop_readintegerLL n = (fst . fromJust . D.readInteger . D.pack . show) n == (n :: Integer)
 
-prop_readinteger2BB s =
+prop_readinteger2BB (String8 s) =
     let s' = filter (\c -> c `notElem` ['0'..'9']) s
     in C.readInteger (C.pack s') == Nothing
 
@@ -1274,7 +1316,8 @@
 -- prop_joinjoinpathBB xs ys c = C.joinWithChar c xs ys == C.join (C.singleton c) [xs,ys]
 
 prop_zipBB  xs ys = zip xs ys == P.zip (P.pack xs) (P.pack ys)
-prop_zipLC  xs ys = zip xs ys == LC.zip (LC.pack xs) (LC.pack ys)
+prop_zipLC (String8 xs) (String8 ys)
+                  = zip xs ys == LC.zip (LC.pack xs) (LC.pack ys)
 prop_zip1BB xs ys = P.zip xs ys == zip (P.unpack xs) (P.unpack ys)
 
 prop_zipWithBB xs ys = P.zipWith (,) xs ys == P.zip xs ys
@@ -1301,9 +1344,12 @@
 ------------------------------------------------------------------------
 
 -- Test IsString, Show, Read, pack, unpack
-prop_isstring x = C.unpack (fromString x :: C.ByteString) == x
-prop_isstring_lc x = LC.unpack (fromString x :: LC.ByteString) == x
+prop_isstring    :: String8 -> Bool
+prop_isstring_lc :: String8 -> Bool
 
+prop_isstring    (String8 x) = C.unpack  (fromString x :: C.ByteString) == x
+prop_isstring_lc (String8 x) = LC.unpack (fromString x :: LC.ByteString) == x
+
 prop_showP1 x = show x == show (C.unpack x)
 prop_showL1 x = show x == show (LC.unpack x)
 
@@ -1316,14 +1362,14 @@
 prop_packunpack_s x = (P.unpack . P.pack) x == x
 prop_unpackpack_s x = (P.pack . P.unpack) x == x
 
-prop_packunpack_c x = (C.unpack . C.pack) x == x
-prop_unpackpack_c x = (C.pack . C.unpack) x == x
+prop_packunpack_c (String8 x) = (C.unpack . C.pack) x == x
+prop_unpackpack_c          x  = (C.pack . C.unpack) x == x
 
 prop_packunpack_l x = (L.unpack . L.pack) x == x
 prop_unpackpack_l x = (L.pack . L.unpack) x == x
 
-prop_packunpack_lc x = (LC.unpack . LC.pack) x == x
-prop_unpackpack_lc x = (LC.pack . LC.unpack) x == x
+prop_packunpack_lc (String8 x) = (LC.unpack . LC.pack) x == x
+prop_unpackpack_lc          x  = (LC.pack . LC.unpack) x == x
 
 prop_toFromChunks x = (L.fromChunks . L.toChunks) x == x
 prop_fromToChunks x = (L.toChunks . L.fromChunks) x == filter (not . P.null) x
@@ -1339,7 +1385,7 @@
        && P.pack (take n cs) == bs
        && drop n cs == cs'
 
-prop_packUptoLenChars cs =
+prop_packUptoLenChars (String8 cs) =
     forAll (choose (0, length cs + 1)) $ \n ->
       let (bs, cs') = P.packUptoLenChars n cs
        in P.length bs == min n (length cs)
@@ -1350,21 +1396,21 @@
 prop_unpack_s cs =
     forAll (choose (0, length cs)) $ \n ->
       P.unpack (P.drop n $ P.pack cs) == drop n cs
-prop_unpack_c cs =
+prop_unpack_c (String8 cs) =
     forAll (choose (0, length cs)) $ \n ->
       C.unpack (C.drop n $ C.pack cs) == drop n cs
 
 prop_unpack_l  cs =
     forAll (choose (0, length cs)) $ \n ->
       L.unpack (L.drop (fromIntegral n) $ L.pack cs) == drop n cs
-prop_unpack_lc cs =
+prop_unpack_lc (String8 cs) =
     forAll (choose (0, length cs)) $ \n ->
       LC.unpack (L.drop (fromIntegral n) $ LC.pack cs) == drop n cs
 
 prop_unpackBytes cs =
     forAll (choose (0, length cs)) $ \n ->
       P.unpackBytes (P.drop n $ P.pack cs) == drop n cs
-prop_unpackChars cs =
+prop_unpackChars (String8 cs) =
     forAll (choose (0, length cs)) $ \n ->
       P.unpackChars (P.drop n $ C.pack cs) == drop n cs
 
@@ -1373,7 +1419,7 @@
     forAll (choose (0, length cs)) $ \n ->
       L.unpackBytes (L.drop (fromIntegral n) $ L.pack cs) == drop n cs
 prop_unpackChars_l =
-    forAll (sized $ \n -> resize (n * 10) arbitrary) $ \cs ->
+    forAll (sized $ \n -> resize (n * 10) arbitrary) $ \(String8 cs) ->
     forAll (choose (0, length cs)) $ \n ->
       L.unpackChars (L.drop (fromIntegral n) $ LC.pack cs) == drop n cs
 
@@ -1381,8 +1427,8 @@
     forAll (sized $ \n -> resize (n * 10) arbitrary) $ \cs ->
     forAll (choose (0, 2)) $ \n ->
       P.unpackAppendBytesLazy (P.drop n $ P.pack cs) cs' == drop n cs ++ cs'
-prop_unpackAppendCharsLazy cs' =
-    forAll (sized $ \n -> resize (n * 10) arbitrary) $ \cs ->
+prop_unpackAppendCharsLazy (String8 cs') =
+    forAll (sized $ \n -> resize (n * 10) arbitrary) $ \(String8 cs) ->
     forAll (choose (0, 2)) $ \n ->
       P.unpackAppendCharsLazy (P.drop n $ C.pack cs) cs' == drop n cs ++ cs'
 
@@ -1390,7 +1436,7 @@
     forAll (choose (0, length cs)) $ \n ->
       P.unpackAppendBytesStrict (P.drop n $ P.pack cs) cs' == drop n cs ++ cs'
 
-prop_unpackAppendCharsStrict cs cs' =
+prop_unpackAppendCharsStrict (String8 cs) (String8 cs') =
     forAll (choose (0, length cs)) $ \n ->
       P.unpackAppendCharsStrict (P.drop n $ C.pack cs) cs' == drop n cs ++ cs'
 
@@ -1701,18 +1747,18 @@
     ]
 
 misc_tests =
-    [ testProperty "packunpack"             prop_packunpack_s
-    , testProperty "unpackpack"             prop_unpackpack_s
-    , testProperty "packunpack"             prop_packunpack_c
-    , testProperty "unpackpack"             prop_unpackpack_c
-    , testProperty "packunpack"             prop_packunpack_l
-    , testProperty "unpackpack"             prop_unpackpack_l
-    , testProperty "packunpack"             prop_packunpack_lc
-    , testProperty "unpackpack"             prop_unpackpack_lc
-    , testProperty "unpack"                 prop_unpack_s
-    , testProperty "unpack"                 prop_unpack_c
-    , testProperty "unpack"                 prop_unpack_l
-    , testProperty "unpack"                 prop_unpack_lc
+    [ testProperty "packunpack (bytes)"     prop_packunpack_s
+    , testProperty "unpackpack (bytes)"     prop_unpackpack_s
+    , testProperty "packunpack (chars)"     prop_packunpack_c
+    , testProperty "unpackpack (chars)"     prop_unpackpack_c
+    , testProperty "packunpack (lazy bytes)" prop_packunpack_l
+    , testProperty "unpackpack (lazy bytes)" prop_unpackpack_l
+    , testProperty "packunpack (lazy chars)" prop_packunpack_lc
+    , testProperty "unpackpack (lazy chars)" prop_unpackpack_lc
+    , testProperty "unpack (bytes)"         prop_unpack_s
+    , testProperty "unpack (chars)"         prop_unpack_c
+    , testProperty "unpack (lazy bytes)"    prop_unpack_l
+    , testProperty "unpack (lazy chars)"    prop_unpack_lc
     , testProperty "packUptoLenBytes"       prop_packUptoLenBytes
     , testProperty "packUptoLenChars"       prop_packUptoLenChars
     , testProperty "unpackBytes"            prop_unpackBytes
@@ -2313,7 +2359,7 @@
     , testProperty "reverse"            prop_reverse
     , testProperty "reverse1"           prop_reverse1
     , testProperty "reverse2"           prop_reverse2
---  , testProperty "transpose"          prop_transpose
+    , testProperty "transpose"          prop_transpose
     , testProperty "foldl"              prop_foldl
     , testProperty "foldl/reverse"      prop_foldl_1
     , testProperty "foldr"              prop_foldr
@@ -2331,7 +2377,7 @@
     , testProperty "all"                prop_all
     , testProperty "maximum"            prop_maximum
     , testProperty "minimum"            prop_minimum
---  , testProperty "replicate 1"        prop_replicate1
+    , testProperty "replicate 1"        prop_replicate1
     , testProperty "replicate 2"        prop_replicate2
     , testProperty "take"               prop_take1
     , testProperty "drop"               prop_drop1
diff --git a/tests/QuickCheckUtils.hs b/tests/QuickCheckUtils.hs
--- a/tests/QuickCheckUtils.hs
+++ b/tests/QuickCheckUtils.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE CPP, MultiParamTypeClasses,
-             FlexibleInstances, TypeSynonymInstances #-}
+             FlexibleInstances, FlexibleContexts,
+             TypeSynonymInstances #-}
 --
 -- Uses multi-param type classes
 --
@@ -62,15 +63,37 @@
   deriving Show
 
 instance Arbitrary CByteString where
-  arbitrary = fmap (CByteString . P.pack . map fromCChar) arbitrary
+  arbitrary = fmap (CByteString . P.pack . map fromCChar)
+                   arbitrary
     where
-      fromCChar :: CChar -> Word8
-      fromCChar = fromIntegral
+      fromCChar :: NonZero CChar -> Word8
+      fromCChar = fromIntegral . getNonZero
 
-instance Arbitrary CChar where
-  arbitrary = fmap (fromIntegral :: Int -> CChar)
-            $ oneof [choose (-128,-1), choose (1,127)]
+-- | 'Char', but only representing 8-bit characters.
+--
+newtype Char8 = Char8 Char
+  deriving (Eq, Ord, Show)
 
+instance Arbitrary Char8 where
+  arbitrary = fmap (Char8 . toChar) arbitrary
+    where
+      toChar :: Word8 -> Char
+      toChar = toEnum . fromIntegral
+
+instance CoArbitrary Char8 where
+  coarbitrary (Char8 c) = coarbitrary c
+
+-- | 'Char', but only representing 8-bit characters.
+--
+newtype String8 = String8 String
+  deriving (Eq, Ord, Show)
+
+instance Arbitrary String8 where
+  arbitrary = fmap (String8 . map toChar) arbitrary
+    where
+      toChar :: Word8 -> Char
+      toChar = toEnum . fromIntegral
+
 ------------------------------------------------------------------------
 --
 -- We're doing two forms of testing here. Firstly, model based testing.
@@ -89,8 +112,13 @@
 --
 --
 class Model a b where
-  model :: a -> b  -- get the abstract vale from a concrete value
+  model :: a -> b  -- ^ Get the abstract value from a concrete value
 
+-- | Alias for 'model' that's a better name in the situations where we're
+-- really just converting functions that take or return Char8.
+castFn :: Model a b => a -> b
+castFn = model
+
 --
 -- Connecting our Lazy and Strict types to their models. We also check
 -- the data invariant on Lazy types.
@@ -102,7 +130,7 @@
 instance Model P [Char] where model = PC.unpack
 instance Model B [W]    where model = L.unpack  . checkInvariant
 instance Model B [Char] where model = LC.unpack . checkInvariant
-instance Model Char Word8 where model = fromIntegral . ord
+instance Model Char8 Char where model (Char8 c) = c
 
 -- Types are trivially modeled by themselves
 instance Model Bool  Bool         where model = id
@@ -123,6 +151,7 @@
 instance NatTrans Maybe Maybe       where eta = id
 instance NatTrans ((->) X) ((->) X) where eta = id
 instance NatTrans ((->) Char) ((->) Char) where eta = id
+instance NatTrans ((->) Char8) ((->) Char) where eta f = f . Char8
 
 instance NatTrans ((->) W) ((->) W) where eta = id
 
diff --git a/tests/builder/Data/ByteString/Builder/Tests.hs b/tests/builder/Data/ByteString/Builder/Tests.hs
--- a/tests/builder/Data/ByteString/Builder/Tests.hs
+++ b/tests/builder/Data/ByteString/Builder/Tests.hs
@@ -51,7 +51,8 @@
 #endif
 
 import           Test.QuickCheck
-                   ( Arbitrary(..), oneof, choose, listOf, elements )
+                   ( Arbitrary(..), oneof, choose, listOf, elements
+                   , UnicodeString(..) )
 import           Test.QuickCheck.Property
                    ( printTestCase, morallyDubiousIOProperty )
 
@@ -96,8 +97,11 @@
 testHandlePutBuilder =
     testProperty "hPutBuilder" testRecipe
   where
-    testRecipe :: (String, String, String, Recipe) -> Bool
-    testRecipe args@(before, between, after, recipe) = unsafePerformIO $ do
+    testRecipe :: (UnicodeString, UnicodeString, UnicodeString, Recipe) -> Bool
+    testRecipe args@(UnicodeString before,
+                     UnicodeString between,
+                     UnicodeString after, recipe) =
+      unsafePerformIO $ do
         tempDir <- getTemporaryDirectory
         (tempFile, tempH) <- openTempFile tempDir "TestBuilder"
         -- switch to UTF-8 encoding
@@ -299,7 +303,7 @@
       , W8  <$> arbitrary
       , W8S <$> listOf arbitrary
         -- ensure that larger character codes are also tested
-      , String <$> listOf ((\c -> chr (ord c * ord c)) <$> arbitrary)
+      , String . getUnicodeString <$> arbitrary
       , pure Flush
         -- never request more than 64kb free space
       , (EnsureFree . (`mod` 0xffff)) <$> arbitrary
