summaryrefslogtreecommitdiff
path: root/libraries/base/GHC/ForeignPtr.hs
diff options
context:
space:
mode:
authorEric Seidel <gridaphobe@gmail.com>2015-12-23 10:10:04 +0100
committerBen Gamari <ben@smart-cactus.org>2015-12-23 11:30:42 +0100
commit380b25ea4754c2aea683538ffdb179f8946219a0 (patch)
tree722784415e0f1b29a46fc115baff56f3495c0c9b /libraries/base/GHC/ForeignPtr.hs
parent78248702b0b8189d73f08c89d86f5cb7a3c6ae8c (diff)
downloadhaskell-380b25ea4754c2aea683538ffdb179f8946219a0.tar.gz
Allow CallStacks to be frozen
This introduces "freezing," an operation which prevents further locations from being appended to a CallStack. Library authors may want to prevent CallStacks from exposing implementation details, as a matter of hygiene. For example, in ``` head [] = error "head: empty list" ghci> head [] *** Exception: head: empty list CallStack (from implicit params): error, called at ... ``` including the call-site of `error` in `head` is not strictly necessary as the error message already specifies clearly where the error came from. So we add a function `freezeCallStack` that wraps an existing CallStack, preventing further call-sites from being pushed onto it. In other words, ``` pushCallStack callSite (freezeCallStack callStack) = freezeCallStack callStack ``` Now we can define `head` to not produce a CallStack at all ``` head [] = let ?callStack = freezeCallStack emptyCallStack in error "head: empty list" ghci> head [] *** Exception: head: empty list CallStack (from implicit params): error, called at ... ``` --- 1. We add the `freezeCallStack` and `emptyCallStack` and update the definition of `CallStack` to support this functionality. 2. We add `errorWithoutStackTrace`, a variant of `error` that does not produce a stack trace, using this feature. I think this is a sensible wrapper function to provide in case users want it. 3. We replace uses of `error` in base with `errorWithoutStackTrace`. The rationale is that base does not export any functions that use CallStacks (except for `error` and `undefined`) so there's no way for the stack traces (from Implicit CallStacks) to include user-defined functions. They'll only contain the call to `error` itself. As base already has a good habit of providing useful error messages that name the triggering function, the stack trace really just adds noise to the error. (I don't have a strong opinion on whether we should include this third commit, but the change was very mechanical so I thought I'd include it anyway in case there's interest) 4. Updates tests in `array` and `stm` submodules Test Plan: ./validate, new test is T11049 Reviewers: simonpj, nomeata, goldfire, austin, hvr, bgamari Reviewed By: simonpj Subscribers: thomie Projects: #ghc Differential Revision: https://phabricator.haskell.org/D1628 GHC Trac Issues: #11049
Diffstat (limited to 'libraries/base/GHC/ForeignPtr.hs')
-rw-r--r--libraries/base/GHC/ForeignPtr.hs22
1 files changed, 11 insertions, 11 deletions
diff --git a/libraries/base/GHC/ForeignPtr.hs b/libraries/base/GHC/ForeignPtr.hs
index d0688f0cbf..6d03967d3b 100644
--- a/libraries/base/GHC/ForeignPtr.hs
+++ b/libraries/base/GHC/ForeignPtr.hs
@@ -153,7 +153,7 @@ mallocForeignPtr :: Storable a => IO (ForeignPtr a)
mallocForeignPtr = doMalloc undefined
where doMalloc :: Storable b => b -> IO (ForeignPtr b)
doMalloc a
- | I# size < 0 = error "mallocForeignPtr: size must be >= 0"
+ | I# size < 0 = errorWithoutStackTrace "mallocForeignPtr: size must be >= 0"
| otherwise = do
r <- newIORef NoFinalizers
IO $ \s ->
@@ -168,7 +168,7 @@ mallocForeignPtr = doMalloc undefined
-- size of the memory required is given explicitly as a number of bytes.
mallocForeignPtrBytes :: Int -> IO (ForeignPtr a)
mallocForeignPtrBytes size | size < 0 =
- error "mallocForeignPtrBytes: size must be >= 0"
+ errorWithoutStackTrace "mallocForeignPtrBytes: size must be >= 0"
mallocForeignPtrBytes (I# size) = do
r <- newIORef NoFinalizers
IO $ \s ->
@@ -182,7 +182,7 @@ mallocForeignPtrBytes (I# size) = do
-- bytes.
mallocForeignPtrAlignedBytes :: Int -> Int -> IO (ForeignPtr a)
mallocForeignPtrAlignedBytes size _align | size < 0 =
- error "mallocForeignPtrAlignedBytes: size must be >= 0"
+ errorWithoutStackTrace "mallocForeignPtrAlignedBytes: size must be >= 0"
mallocForeignPtrAlignedBytes (I# size) (I# align) = do
r <- newIORef NoFinalizers
IO $ \s ->
@@ -208,7 +208,7 @@ mallocPlainForeignPtr :: Storable a => IO (ForeignPtr a)
mallocPlainForeignPtr = doMalloc undefined
where doMalloc :: Storable b => b -> IO (ForeignPtr b)
doMalloc a
- | I# size < 0 = error "mallocForeignPtr: size must be >= 0"
+ | I# size < 0 = errorWithoutStackTrace "mallocForeignPtr: size must be >= 0"
| otherwise = IO $ \s ->
case newAlignedPinnedByteArray# size align s of { (# s', mbarr# #) ->
(# s', ForeignPtr (byteArrayContents# (unsafeCoerce# mbarr#))
@@ -223,7 +223,7 @@ mallocPlainForeignPtr = doMalloc undefined
-- exception to be thrown.
mallocPlainForeignPtrBytes :: Int -> IO (ForeignPtr a)
mallocPlainForeignPtrBytes size | size < 0 =
- error "mallocPlainForeignPtrBytes: size must be >= 0"
+ errorWithoutStackTrace "mallocPlainForeignPtrBytes: size must be >= 0"
mallocPlainForeignPtrBytes (I# size) = IO $ \s ->
case newPinnedByteArray# size s of { (# s', mbarr# #) ->
(# s', ForeignPtr (byteArrayContents# (unsafeCoerce# mbarr#))
@@ -236,7 +236,7 @@ mallocPlainForeignPtrBytes (I# size) = IO $ \s ->
-- exception to be thrown.
mallocPlainForeignPtrAlignedBytes :: Int -> Int -> IO (ForeignPtr a)
mallocPlainForeignPtrAlignedBytes size _align | size < 0 =
- error "mallocPlainForeignPtrAlignedBytes: size must be >= 0"
+ errorWithoutStackTrace "mallocPlainForeignPtrAlignedBytes: size must be >= 0"
mallocPlainForeignPtrAlignedBytes (I# size) (I# align) = IO $ \s ->
case newAlignedPinnedByteArray# size align s of { (# s', mbarr# #) ->
(# s', ForeignPtr (byteArrayContents# (unsafeCoerce# mbarr#))
@@ -250,7 +250,7 @@ addForeignPtrFinalizer :: FinalizerPtr a -> ForeignPtr a -> IO ()
addForeignPtrFinalizer (FunPtr fp) (ForeignPtr p c) = case c of
PlainForeignPtr r -> insertCFinalizer r fp 0# nullAddr# p ()
MallocPtr _ r -> insertCFinalizer r fp 0# nullAddr# p c
- _ -> error "GHC.ForeignPtr: attempt to add a finalizer to a plain pointer"
+ _ -> errorWithoutStackTrace "GHC.ForeignPtr: attempt to add a finalizer to a plain pointer"
-- Note [MallocPtr finalizers] (#10904)
--
@@ -270,7 +270,7 @@ addForeignPtrFinalizerEnv ::
addForeignPtrFinalizerEnv (FunPtr fp) (Ptr ep) (ForeignPtr p c) = case c of
PlainForeignPtr r -> insertCFinalizer r fp 1# ep p ()
MallocPtr _ r -> insertCFinalizer r fp 1# ep p c
- _ -> error "GHC.ForeignPtr: attempt to add a finalizer to a plain pointer"
+ _ -> errorWithoutStackTrace "GHC.ForeignPtr: attempt to add a finalizer to a plain pointer"
addForeignPtrConcFinalizer :: ForeignPtr a -> IO () -> IO ()
-- ^This function adds a finalizer to the given @ForeignPtr@. The
@@ -311,7 +311,7 @@ addForeignPtrConcFinalizer_ f@(MallocPtr fo r) finalizer = do
finalizer' = unIO (foreignPtrFinalizer r >> touch f)
addForeignPtrConcFinalizer_ _ _ =
- error "GHC.ForeignPtr: attempt to add a finalizer to plain pointer"
+ errorWithoutStackTrace "GHC.ForeignPtr: attempt to add a finalizer to plain pointer"
insertHaskellFinalizer :: IORef Finalizers -> IO () -> IO Bool
insertHaskellFinalizer r f = do
@@ -358,7 +358,7 @@ ensureCFinalizerWeak ref@(IORef (STRef r#)) value = do
update _ _ = noMixingError
noMixingError :: a
-noMixingError = error $
+noMixingError = errorWithoutStackTrace $
"GHC.ForeignPtr: attempt to mix Haskell and C finalizers " ++
"in the same ForeignPtr"
@@ -441,5 +441,5 @@ finalizeForeignPtr (ForeignPtr _ foreignPtr) = foreignPtrFinalizer refFinalizers
(PlainForeignPtr ref) -> ref
(MallocPtr _ ref) -> ref
PlainPtr _ ->
- error "finalizeForeignPtr PlainPtr"
+ errorWithoutStackTrace "finalizeForeignPtr PlainPtr"