【问题标题】:Segfault in Haskell LLVM-General code generationHaskell LLVM-General 代码生成中的 Segfault
【发布时间】:2014-07-01 01:34:45
【问题描述】:

我正在尝试遵循LLVM bindings 教程here,但遇到了段错误。下面的代码工作,因为它将模块头打印到output.ll,但它也在某个地方出现了段错误。

module Main where

import Control.Monad.Error
import LLVM.General.Module
import LLVM.General.Context
import qualified LLVM.General.AST as AST

--Create and write out an empty LLVM module
main :: IO ()
main = writeModule (AST.defaultModule { AST.moduleName = "myModule" })

outputFile :: File
outputFile = File "output.ll"

writeModule :: AST.Module -> IO ()
writeModule mod = withContext $ (\context ->
                    liftError $ withModuleFromAST context mod (\m ->
                      liftError $ writeLLVMAssemblyToFile outputFile m))

--perform the action, or fail on an error
liftError :: ErrorT String IO a -> IO a
liftError = runErrorT >=> either fail return

我怀疑这与链接教程中的以下提示有关:

记住不要传递或尝试使用括号外的资源非常重要,因为这会导致未定义的行为和/或段错误。

我认为在这种情况下,“括号”是由 withContext 函数实现的,这使得看起来一切都应该处理。

如果我将writeModule 的定义更改为

writeModule mod = do assembly <- (withContext $ (\context ->
                       liftError $ withModuleFromAST context mod moduleLLVMAssembly))
                    putStrLn assembly

也就是说,我只是打印出 LLVM 程序集的字符串表示,而不是写入文件,不会引发段错误。

有人对这些绑定有经验吗?我也有兴趣了解我引用的警告的失败案例。也就是说,一个人怎么会“忘记”不使用括号外的资源?似乎需要Context 的所有功能都需要一个。这种资源范围问题不正是 Haskell 擅长为您处理的吗?

版本信息:

  • llvm-general-3.4.3.0
  • LLVM version 3.4
  • Default target: x86_64-apple-darwin13.2.0

【问题讨论】:

  • 我猜bracket pattern 上的页面支持我对括号内容的直觉,其中指出“通常,在整个库中,定义了许多名称以 with 开头的函数来管理各种以这种方式获取资源。”
  • 与您的问题无关:为什么您将 writeModule 中的所有内容都包装在一个琐碎的 do 块中?
  • 糟糕,这可能是编辑错误。

标签: haskell llvm


【解决方案1】:

如果您共享 LLVM 和 cabal 环境会有所帮助,LLVM 因其自身向后不兼容而臭名昭著,因此使用最新版本的绑定可能会出现问题。

在幕后writeLLVMAssemblyToFile 正在使用 C++ 调用来执行文件 IO 操作,我推测它持有对 LLVM 模块的引用作为最终确定文件资源的结果。

尝试使用 moduleString 将模块渲染为字符串,然后只提升到 IO monad 以从 Haskell 调用 writeFile,而不是通过 C++ 进行写入。

import LLVM.General.Context
import LLVM.General.Module as Mod
import qualified LLVM.General.AST as AST

import Control.Monad.Error

main :: IO ()
main = do
  writeModule (AST.defaultModule { AST.moduleName = "myModule" })
  return ()

writeModule :: AST.Module -> IO (Either String ())
writeModule ast =
  withContext $ \ctx ->
    runErrorT $ withModuleFromAST ctx ast $ \m -> do
      asm <- moduleString m
      liftIO $ writeFile "output.ll" asm

根据我的经验,绑定仍然相当脆弱,如果问题仍然存在,您应该在issue tracker 上询问。

编辑:这是针对后来修复的旧版本的解决方法。见:https://github.com/bscarlet/llvm-general/issues/109

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-03
    • 1970-01-01
    • 2015-08-25
    • 1970-01-01
    相关资源
    最近更新 更多