Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix CString use-after-free bugs and memory leaks #13

Merged
merged 2 commits into from
Mar 11, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 20 additions & 21 deletions CMark.hsc
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ import Data.Data (Data)
import Data.Typeable (Typeable)
import Data.Text (Text, empty)
import qualified Data.Text.Foreign as TF
import qualified Data.ByteString as B
import Data.Text.Encoding (encodeUtf8)
import Data.ByteString.Unsafe (unsafePackMallocCString)
import Data.Text.Encoding (decodeUtf8)
import Control.Applicative ((<$>), (<*>))

#include <cmark.h>
Expand Down Expand Up @@ -102,7 +102,7 @@ nodeToX renderer opts mbWidth node = Unsafe.unsafePerformIO $ do
fptr <- newForeignPtr c_cmark_node_free nptr
withForeignPtr fptr $ \ptr -> do
cstr <- renderer ptr (combineOptions opts) (fromMaybe 0 mbWidth)
TF.peekCStringLen (cstr, c_strlen cstr)
decodeUtf8 <$> unsafePackMallocCString cstr

commonmarkToX :: Renderer
-> [CMarkOption]
Expand All @@ -116,8 +116,7 @@ commonmarkToX renderer opts mbWidth s = Unsafe.unsafePerformIO $
fptr <- newForeignPtr c_cmark_node_free nptr
withForeignPtr fptr $ \p -> do
str <- renderer p opts' (fromMaybe 0 mbWidth)
t <- TF.peekCStringLen $! (str, c_strlen str)
return t
decodeUtf8 <$> unsafePackMallocCString str

type NodePtr = Ptr ()

Expand Down Expand Up @@ -317,17 +316,17 @@ fromNode (Node _ nodeType children) = do
BLOCK_QUOTE -> c_cmark_node_new (#const CMARK_NODE_BLOCK_QUOTE)
HTML_BLOCK literal -> do
n <- c_cmark_node_new (#const CMARK_NODE_HTML_BLOCK)
c_cmark_node_set_literal n =<< fromtext literal
withtext literal (c_cmark_node_set_literal n)
return n
CUSTOM_BLOCK onEnter onExit -> do
n <- c_cmark_node_new (#const CMARK_NODE_CUSTOM_BLOCK)
c_cmark_node_set_on_enter n =<< fromtext onEnter
c_cmark_node_set_on_exit n =<< fromtext onExit
withtext onEnter (c_cmark_node_set_on_enter n)
withtext onExit (c_cmark_node_set_on_exit n)
return n
CODE_BLOCK info literal -> do
n <- c_cmark_node_new (#const CMARK_NODE_CODE_BLOCK)
c_cmark_node_set_literal n =<< fromtext literal
c_cmark_node_set_fence_info n =<< fromtext info
withtext literal (c_cmark_node_set_literal n)
withtext info (c_cmark_node_set_fence_info n)
return n
LIST attr -> do
n <- c_cmark_node_new (#const CMARK_NODE_LIST)
Expand All @@ -349,30 +348,30 @@ fromNode (Node _ nodeType children) = do
STRONG -> c_cmark_node_new (#const CMARK_NODE_STRONG)
LINK url title -> do
n <- c_cmark_node_new (#const CMARK_NODE_LINK)
c_cmark_node_set_url n =<< fromtext url
c_cmark_node_set_title n =<< fromtext title
withtext url (c_cmark_node_set_url n)
withtext title (c_cmark_node_set_title n)
return n
IMAGE url title -> do
n <- c_cmark_node_new (#const CMARK_NODE_IMAGE)
c_cmark_node_set_url n =<< fromtext url
c_cmark_node_set_title n =<< fromtext title
withtext url (c_cmark_node_set_url n)
withtext title (c_cmark_node_set_title n)
return n
TEXT literal -> do
n <- c_cmark_node_new (#const CMARK_NODE_TEXT)
c_cmark_node_set_literal n =<< fromtext literal
withtext literal (c_cmark_node_set_literal n)
return n
CODE literal -> do
n <- c_cmark_node_new (#const CMARK_NODE_CODE)
c_cmark_node_set_literal n =<< fromtext literal
withtext literal (c_cmark_node_set_literal n)
return n
HTML_INLINE literal -> do
n <- c_cmark_node_new (#const CMARK_NODE_HTML_INLINE)
c_cmark_node_set_literal n =<< fromtext literal
withtext literal (c_cmark_node_set_literal n)
return n
CUSTOM_INLINE onEnter onExit -> do
n <- c_cmark_node_new (#const CMARK_NODE_CUSTOM_INLINE)
c_cmark_node_set_on_enter n =<< fromtext onEnter
c_cmark_node_set_on_exit n =<< fromtext onExit
withtext onEnter (c_cmark_node_set_on_enter n)
withtext onExit (c_cmark_node_set_on_exit n)
return n
SOFTBREAK -> c_cmark_node_new (#const CMARK_NODE_SOFTBREAK)
LINEBREAK -> c_cmark_node_new (#const CMARK_NODE_LINEBREAK)
Expand All @@ -384,8 +383,8 @@ totext str
| str == nullPtr = return empty
| otherwise = TF.peekCStringLen (str, c_strlen str)

fromtext :: Text -> IO CString
fromtext t = B.useAsCString (encodeUtf8 t) return
withtext :: Text -> (CString -> IO a) -> IO a
withtext t f = TF.withCStringLen t (f . fst)

foreign import ccall "string.h strlen"
c_strlen :: CString -> Int
Expand Down