You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非托管函数指针返回时触发SIGSEGV(段错误)问题排查

解决C#调用OpenSSL回调时的SIGSEGV段错误问题

看起来你的问题核心出在委托签名不匹配,加上可能存在的委托被GC回收的隐患,导致回调返回时栈损坏或者访问无效内存,触发段错误。我们一步步拆解问题并修复:

1. 核心问题:委托签名与C函数不匹配

原C语言的回调函数签名是:

int (*cb) (SSL *ssl, const unsigned char *cookie, unsigned int cookie_len)

而你最初定义的C#委托是:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int VerifyCookieDelegate(IntPtr ssl, [MarshalAs(UnmanagedType.LPStr)] string cookie, int cookie_len);

这里的关键错误是:

  • const unsigned char *cookie是二进制缓冲区,不是以\0结尾的字符串,你用[MarshalAs(UnmanagedType.LPStr)] string会让.NET自动尝试从指针读取到null终止符,这会直接越界读取cookie_len之外的内存,破坏进程空间,最终在回调返回时触发SIGSEGV。

2. 修复步骤

第一步:修正委托签名

把cookie参数改为IntPtr,完全匹配C语言的指针类型,手动处理二进制数据:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int VerifyCookieDelegate(IntPtr ssl, IntPtr cookie, int cookie_len);

这样.NET不会自动做字符串marshal,避免越界读取的问题。

第二步:确保委托实例不被GC回收

如果你只是临时创建委托并传递给原生函数,.NET的GC可能会在回调被调用前回收这个委托实例,导致原生代码调用无效的函数指针,同样会触发段错误。需要把委托实例保存到一个长期存在的变量中,比如类的成员:

// 类成员变量,保存委托实例防止GC回收
private VerifyCookieDelegate _persistedVerifyCookieDelegate;

// 设置回调的代码
public void SetCookieVerifyCallback(IntPtr ctxPtr)
{
    _persistedVerifyCookieDelegate = VerifyCookieThunk;
    SSL_CTX_set_cookie_verify_cb(ctxPtr, _persistedVerifyCookieDelegate);
}

第三步:确认回调实现的细节

你的VerifyCookieThunk实现已经用IntPtr处理cookie,这部分是正确的,但要注意:

  • 确保Marshal.Copy的参数没有越界(你当前的代码是对的)
  • 确认返回值和C代码的约定一致:C代码中返回1表示验证通过,0表示失败,你的返回逻辑要对应(比如Native.FAIL的值要和C代码的失败返回值匹配)

3. 验证修复后的完整代码示例

private const string SSLDLLNAME = "libssl.so"; // 或者对应Windows的libssl.dll

[DllImport(SSLDLLNAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void SSL_CTX_set_cookie_verify_cb(IntPtr ctx, VerifyCookieDelegate callback);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int VerifyCookieDelegate(IntPtr ssl, IntPtr cookie, int cookie_len);

// 保存委托实例,防止GC回收
private VerifyCookieDelegate _persistedVerifyCookieDelegate;
private Func<Ssl, byte[], bool> _verifyCookieCallback;

public void InitializeVerifyCallback(IntPtr ctxPtr, Func<Ssl, byte[], bool> verifyCallback)
{
    _verifyCookieCallback = verifyCallback;
    _persistedVerifyCookieDelegate = VerifyCookieThunk;
    SSL_CTX_set_cookie_verify_cb(ctxPtr, _persistedVerifyCookieDelegate);
}

public int VerifyCookieThunk(IntPtr sslPtr, IntPtr cookie, int cookieLength)
{
    if (!TryGetInstance(sslPtr, out Ssl ssl)) return Native.FAIL;
    var cookieBytes = new byte[cookieLength];
    Marshal.Copy(cookie, cookieBytes, 0, cookieLength);
    return _verifyCookieCallback(ssl, cookieBytes) ? 1 : 0;
}

这样修改后,委托签名完全匹配C函数,且委托实例不会被GC回收,应该就能解决回调返回时的SIGSEGV问题了。

内容的提问来源于stack exchange,提问作者Matthew Goulart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:23:55