首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 呼叫 Haskell 發生 AccessViolationException:問題重現與程式碼分析

     編輯:關於C#

問題重現環境

  • Haskell:GHC 7.6.3, Pandoc 庫
  • C 封裝層:提供 DLL 匯出進入點
  • C#:.NET Framework, DllImport 呼叫

Haskell 核心代碼


-- LibPandoc.hs
module LibPandoc where

import Text.Pandoc
import Foreign.C.String
import Foreign.Ptr

foreign export ccall markdownToHtml :: CString -> IO CString

markdownToHtml :: CString -> IO CString
markdownToHtml cstr = do
    md <- peekCString cstr
    -- Pandoc 處理 Markdown -> HTML
    html <- runIOorThrow $ do
        doc <- readMarkdown def md
        writeHtmlString def doc
    newCString html  -- 關鍵:配置新字串並回傳指標

C 封裝層 (pandoc.c)


#include 
#include 

extern void __stginit_LibPandoc(void);

BOOL STDCALL DllMain(HANDLE hModule, DWORD reason, void* reserved)
{
    static char* args[] = {"libpandoc", NULL};
    if (reason == DLL_PROCESS_ATTACH)
    {
        startupHaskell(1, args, __stginit_LibPandoc);
    }
    return TRUE;
}

GHC 產生的 Stub Header


#include "HsFFI.h"
#ifdef __cplusplus
extern "C" {
#endif
extern HsPtr markdownToHtml(HsPtr a1);
#ifdef __cplusplus
}
#endif

C# 呼叫代碼


class Native
{
    [DllImport("libpandoc", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
    public static extern IntPtr markdownToHtml(byte[] markdown);
}

public class Processor
{
    public string Process(string text)
    {
        var intPtr = Native.markdownToHtml(Encoding.UTF8.GetBytes(text));
        var html = Marshal.PtrToStringAnsi(intPtr); // 疑點:CharSet.Unicode vs Ansi
        return html;
    }
}

錯誤現象


System.AccessViolationException: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.

關鍵疑點分析

項目現狀潛在問題
CharSetC#: Unicode, Haskell: CString (Latin-1/ASCII)編碼不匹配導致記憶體誤讀
記憶體所有權Haskell 配置 (newCString),C# 負責釋放?缺少釋放函式匯出,造成洩漏或雙重釋放
CallingConventionCdecl (雙方一致)正確
Haskell RuntimeDllMain 啟動 startupHaskell單執行緒模式,並發呼叫會衝突
GHC 版本7.6.3 (2013)較舊,Windows 相容性有已知問題
OS 環境WS2008 R2 編譯/執行失敗,WS2012 成功載入器/記憶體管理差異

後續解決方向(見 10725 完整解決)

  1. 修正 CharSet:C# 改 CharSet.Ansi 或 Haskell 改用 CWString (UTF-16)
  2. 匯出釋放函式:foreign export ccall freeHaskellString :: CString -> IO ()
  3. 升級 GHC 至 9.x,重新編譯
  4. 遷移至 Windows Server 2012+ 或 Linux 容器
  5. 改用進程隔離:C# 呼叫 pandoc CLI 或 HTTP 微服務

此為問題重現與程式碼分析記錄,完整解決過程請參考「C# 呼叫 Haskell 遭遇嘗試讀取或寫入受保護的記憶體:竟是 Windows Server 2008 的坑」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved