diff --git a/Data/Attoparsec/ByteString/Buffer.hs b/Data/Attoparsec/ByteString/Buffer.hs
--- a/Data/Attoparsec/ByteString/Buffer.hs
+++ b/Data/Attoparsec/ByteString/Buffer.hs
@@ -65,6 +65,7 @@
 import GHC.ForeignPtr (mallocPlainForeignPtrBytes)
 import Prelude hiding (length)
 
+-- If _cap is zero, this buffer is empty.
 data Buffer = Buf {
       _fp  :: {-# UNPACK #-} !(ForeignPtr Word8)
     , _off :: {-# UNPACK #-} !Int
@@ -96,7 +97,7 @@
     mconcat xs = foldl1' mappend xs
 
 pappend :: Buffer -> ByteString -> Buffer
-pappend (Buf _ _ _ 0 _) (PS fp off len) = Buf fp off len 0 0
+pappend (Buf _ _ _ 0 _) bs  = buffer bs
 pappend buf (PS fp off len) = append buf fp off len
 
 append :: Buffer -> ForeignPtr a -> Int -> Int -> Buffer
diff --git a/Data/Attoparsec/Internal.hs b/Data/Attoparsec/Internal.hs
--- a/Data/Attoparsec/Internal.hs
+++ b/Data/Attoparsec/Internal.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, BangPatterns, ScopedTypeVariables #-}
+{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}
 -- |
 -- Module      :  Data.Attoparsec.Internal
 -- Copyright   :  Bryan O'Sullivan 2007-2014
@@ -22,11 +22,9 @@
     ) where
 
 import Control.Applicative ((<$>))
-#if __GLASGOW_HASKELL__ >= 700
+import Data.Attoparsec.Internal.Types
 import Data.ByteString (ByteString)
 import Data.Text (Text)
-#endif
-import Data.Attoparsec.Internal.Types
 import Prelude hiding (succ)
 
 -- | Compare two 'IResult' values for equality.
@@ -53,7 +51,6 @@
   if nullChunk s
   then lose t pos Complete
   else succ (pappendChunk t s) pos Incomplete
-#if __GLASGOW_HASKELL__ >= 700
 {-# SPECIALIZE prompt :: State ByteString -> Pos -> More
                       -> (State ByteString -> Pos -> More
                           -> IResult ByteString r)
@@ -64,7 +61,6 @@
                       -> (State Text -> Pos -> More -> IResult Text r)
                       -> (State Text -> Pos -> More -> IResult Text r)
                       -> IResult Text r #-}
-#endif
 
 -- | Immediately demand more input via a 'Partial' continuation
 -- result.
@@ -75,10 +71,8 @@
     _ -> let lose' t' pos' more' = lose t' pos' more' [] "not enough input"
              succ' t' pos' more' = succ t' pos' more' ()
          in prompt t pos more lose' succ'
-#if __GLASGOW_HASKELL__ >= 700
 {-# SPECIALIZE demandInput :: Parser ByteString () #-}
 {-# SPECIALIZE demandInput :: Parser Text () #-}
-#endif
 
 -- | This parser always succeeds.  It returns 'True' if any input is
 -- available either immediately or on demand, and 'False' if the end
@@ -103,10 +97,8 @@
        let lose' t' pos' more' _ctx _msg = succ t' pos' more' ()
            succ' t' pos' more' _a = lose t' pos' more' [] "endOfInput"
        in  runParser demandInput t pos more lose' succ'
-#if __GLASGOW_HASKELL__ >= 700
 {-# SPECIALIZE endOfInput :: Parser ByteString () #-}
 {-# SPECIALIZE endOfInput :: Parser Text () #-}
-#endif
 
 -- | Return an indication of whether the end of input has been
 -- reached.
@@ -127,7 +119,6 @@
             Just (e, l) | p e -> succ' t' (pos' + Pos l) more' e
                         | otherwise -> lose' t' pos' more' [] "satisfyElem"
             Nothing -> runParser (demandInput >> go) t' pos' more' lose' succ'
-#if __GLASGOW_HASKELL__ >= 700
 {-# SPECIALIZE satisfySuspended :: (ChunkElem ByteString -> Bool)
                                 -> State ByteString -> Pos -> More
                                 -> Failure ByteString (State ByteString) r
@@ -140,7 +131,6 @@
                                 -> Success Text (State Text)
                                            (ChunkElem Text) r
                                 -> IResult Text r #-}
-#endif
 
 -- | The parser @satisfyElem p@ succeeds for any chunk element for which the
 -- predicate @p@ returns 'True'. Returns the element that is
diff --git a/Data/Attoparsec/Text/Buffer.hs b/Data/Attoparsec/Text/Buffer.hs
--- a/Data/Attoparsec/Text/Buffer.hs
+++ b/Data/Attoparsec/Text/Buffer.hs
@@ -51,6 +51,7 @@
 import Prelude hiding (length)
 import qualified Data.Text.Array as A
 
+-- If _cap is zero, this buffer is empty.
 data Buffer = Buf {
       _arr :: {-# UNPACK #-} !A.Array
     , _off :: {-# UNPACK #-} !Int
@@ -82,8 +83,8 @@
     mconcat xs = foldl1' mappend xs
 
 pappend :: Buffer -> Text -> Buffer
-pappend (Buf _ _ _ 0 _) (Text arr off len) = Buf arr off len 0 0
-pappend buf (Text arr off len)             = append buf arr off len
+pappend (Buf _ _ _ 0 _) t      = buffer t
+pappend buf (Text arr off len) = append buf arr off len
 
 append :: Buffer -> A.Array -> Int -> Int -> Buffer
 append (Buf arr0 off0 len0 cap0 gen0) !arr1 !off1 !len1 = runST $ do
diff --git a/attoparsec.cabal b/attoparsec.cabal
--- a/attoparsec.cabal
+++ b/attoparsec.cabal
@@ -1,5 +1,5 @@
 name:            attoparsec
-version:         0.12.1.1
+version:         0.12.1.2
 license:         BSD3
 license-file:    LICENSE
 category:        Text, Parsing
@@ -84,6 +84,8 @@
                   QC.ByteString
                   QC.Combinator
                   QC.Common
+                  QC.Rechunked
+                  QC.Simple
                   QC.Text
 
   ghc-options:
@@ -101,7 +103,8 @@
     scientific,
     test-framework >= 0.8.0.2,
     test-framework-quickcheck2 >= 0.3.0.3,
-    text
+    text,
+    vector
 
 benchmark benchmarks
   type: exitcode-stdio-1.0
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,14 @@
+0.12.1.2
+
+* Fixed the incorrect tracking of capacity if the initial buffer was
+  empty (https://github.com/bos/attoparsec/issues/75)
+
+0.12.1.1
+
+* Fixed a data corruption bug that occurred under some circumstances
+  if a buffer grew after prompting for more input
+  (https://github.com/bos/attoparsec/issues/74)
+
 0.12.1.0
 
 * Now compatible with GHC 7.9
diff --git a/tests/QC.hs b/tests/QC.hs
--- a/tests/QC.hs
+++ b/tests/QC.hs
@@ -4,6 +4,7 @@
 import qualified QC.Buffer as Buffer
 import qualified QC.ByteString as ByteString
 import qualified QC.Combinator as Combinator
+import qualified QC.Simple as Simple
 import qualified QC.Text as Text
 import Test.Framework (defaultMain, testGroup)
 
@@ -13,5 +14,6 @@
     testGroup "bs" ByteString.tests
   , testGroup "buf" Buffer.tests
   , testGroup "combinator" Combinator.tests
+  , testGroup "simple" Simple.tests
   , testGroup "text" Text.tests
   ]
diff --git a/tests/QC/Rechunked.hs b/tests/QC/Rechunked.hs
new file mode 100644
--- /dev/null
+++ b/tests/QC/Rechunked.hs
@@ -0,0 +1,55 @@
+{-# LANGUAGE BangPatterns #-}
+
+module QC.Rechunked (
+      rechunkBS
+    , rechunkT
+    ) where
+
+import Control.Monad (forM, forM_)
+import Control.Monad.ST (runST)
+import Data.List (unfoldr)
+import Test.QuickCheck (Gen, choose)
+import qualified Data.ByteString as B
+import qualified Data.Text as T
+import qualified Data.Vector as V
+import qualified Data.Vector.Generic as G
+import qualified Data.Vector.Generic.Mutable as M
+
+rechunkBS :: B.ByteString -> Gen [B.ByteString]
+rechunkBS = fmap (map B.copy) . rechunk_ B.splitAt B.length
+
+rechunkT :: T.Text -> Gen [T.Text]
+rechunkT = fmap (map T.copy) . rechunk_ T.splitAt T.length
+
+rechunk_ :: (Int -> a -> (a,a)) -> (a -> Int) -> a -> Gen [a]
+rechunk_ split len xs = (unfoldr go . (,) xs) `fmap` rechunkSizes (len xs)
+  where go (b,r:rs)   = Just (h, (t,rs))
+          where (h,t) = split r b
+        go (_,_)      = Nothing
+
+rechunkSizes :: Int -> Gen [Int]
+rechunkSizes n0 = shuffle =<< loop [] (0:repeat 1) n0
+  where loop _ [] _ = error "it's 2014, where's my Stream type?"
+        loop acc (lb:lbs) n
+          | n <= 0 = shuffle (reverse acc)
+          | otherwise = do
+            !i <- choose (lb,n)
+            loop (i:acc) lbs (n-i)
+
+shuffle :: [Int] -> Gen [Int]
+shuffle (0:xs) = (0:) `fmap` shuffle xs
+shuffle xs = fisherYates xs
+
+fisherYates :: [a] -> Gen [a]
+fisherYates xs = (V.toList . V.backpermute v) `fmap` swapIndices (G.length v)
+  where
+    v = V.fromList xs
+    swapIndices n0 = do
+        swaps <- forM [0..n] $ \i -> ((,) i) `fmap` choose (i,n)
+        return (runST (swapAll swaps))
+      where
+        n = n0 - 1
+        swapAll ijs = do
+          mv <- G.unsafeThaw (G.enumFromTo 0 n :: V.Vector Int)
+          forM_ ijs $ uncurry (M.swap mv)
+          G.unsafeFreeze mv
diff --git a/tests/QC/Simple.hs b/tests/QC/Simple.hs
new file mode 100644
--- /dev/null
+++ b/tests/QC/Simple.hs
@@ -0,0 +1,37 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+
+module QC.Simple (
+      tests
+    ) where
+
+import Control.Applicative ((<|>))
+import Data.ByteString (ByteString)
+import Data.List (foldl')
+import Data.Maybe (fromMaybe)
+import QC.Rechunked (rechunkBS)
+import Test.Framework (Test)
+import Test.Framework.Providers.QuickCheck2 (testProperty)
+import Test.QuickCheck (Property, counterexample, forAll)
+import qualified Data.Attoparsec.ByteString.Char8 as A
+
+t_issue75 = expect issue75 "ab" (A.Done "" "b")
+
+issue75 :: A.Parser ByteString
+issue75 = "a" >> ("b" <|> "")
+
+expect :: (Show r, Eq r) => A.Parser r -> ByteString -> A.Result r -> Property
+expect p input wanted =
+  forAll (rechunkBS input) $ \in' ->
+    let result = parse p in'
+    in counterexample (show result ++ " /= " ++ show wanted) $
+       fromMaybe False (A.compareResults result wanted)
+
+parse :: A.Parser r -> [ByteString] -> A.Result r
+parse p (x:xs) = foldl' A.feed (A.parse p x) xs
+parse p []     = A.parse p ""
+
+tests :: [Test]
+tests = [
+      testProperty "issue75" t_issue75
+  ]
