cgo 偶发fatal error: unexpected signal during runtime execution

文章描述了一个在Go1.13.5版本中使用cgo调用C语言动态库时遇到的偶发性段错误(SIGSEGV)问题。问题可能与Go和glibc的内存栈处理差异以及并发调用有关。解决方案包括升级Go版本到1.18rc1,或者在调用动态库时确保互斥,如设置GOMAXPROCS=1以限制并发执行。
摘要由CSDN通过智能技术生成

背景

go 版本:go1.13.5 linux/arm64
有一次项目场景需要使用两个c语言动态库,都在同一个package里面,如下所示:

file1.go:
//package main
//
///*
#cgo CFLAGS: -I./include/trustzone -I./openssl/include
#cgo LDFLAGS: -L./lib -lCrypto_sm
#include <stdio.h>
#include <stdlib.h>
#include "crypto_sm_ca.h"
//*/
import "C"
import (
	"unsafe"
)
//
///**
//  CreateAuthModuleRootKey
//  @Description: 创建密钥对,并导出公钥
//  @param path 存储导出公钥的路径
//  @return bool
//*/
func CreateAuthModuleRootKey(path []byte) bool {
	ret := new(C.int)
	pathLen := len(path)

	*ret = C.CreateAuthModuleRootKey((*C.char)(unsafe.Pointer(&path[0])), (C.int)(pathLen))
	if int(*ret) < 0 {
		return false
	}
	return true
}
file2.go:
package main

/*
#cgo CFLAGS: -I./include/libSecIslandtee -I./openssl/include
#cgo LDFLAGS: -L./lib -lSecIslandtee
#include <stdio.h>
#include <stdlib.h>
#include "secisland_tee.h"
*/
import "C"
import (
	"sync"
	"unsafe"
)

/**
  SM2EncryptCGO
  @Description: SM2加密的golang接口
  @param sm2Pubkey	公钥
  @param plainText	明文
  @return []byte	密文
*/
func SM2EncryptCGO(sm2Pubkey, plainText []byte) (bool, []byte) {
	plainTextLen := len(plainText) + 1
	var outbuf = make([]byte, plainTextLen+128)
	cipherTextLen := new(C.int)

	*cipherTextLen = C.SecIsland_TEE_sm2_encrypt_CGO((*C.char)(unsafe.Pointer(&sm2Pubkey[0])),
		(*C.uchar)(unsafe.Pointer(&plainText[0])), (C.int)(plainTextLen), (*C.uchar)(unsafe.Pointer(&outbuf[0])))

	if int(*cipherTextLen) < 0 {
		return false, nil
	}

	return true, outbuf[:int(*cipherTextLen)]
}

偶发panic:

fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x824a0 pc=0x824a0]

runtime stack:
runtime.throw(0x76524a, 0x2a)
        /usr/local/go/src/runtime/panic.go:774 +0x54
runtime.sigpanic()
        /usr/local/go/src/runtime/signal_unix.go:378 +0x458

goroutine 12 [syscall]:
runtime.cgocall(0x69dd98, 0x40001b1508, 0x101)
        /usr/local/go/src/runtime/cgocall.go:128 +0x50 fp=0x40001b14d0 sp=0x40001b1490 pc=0x404e98
main._Cfunc_SecIsland_TEE_sm2_decrypt_CGO(0x40002f2500, 0x4000342000, 0x8b, 0x4000342090, 0x0)
        _cgo_gotypes.go:166 +0x44 fp=0x40001b1500 sp=0x40001b14d0 pc=0x69bf4c
main.SM2DecryptCGO(0x40002f2500, 0x12e, 0x12e, 0x4000342000, 0x8b, 0x8d, 0x400009ed00, 0x0, 0x0, 0x0)
        /data/trustzone-agent/agent-ca/auth-module-trustzone/secislandtee.go:57 +0xf4 fp=0x40001b1580 sp=0x40001b1500 pc=0x69c4cc
main.normalDecryptKey(0x400001cd00, 0x32, 0x4000342000, 0x8b, 0x8d, 0x4000017e80, 0xa, 0x40001c2000, 0x0, 0x0, ...)
        /data/trustzone-agent/agent-ca/auth-module-trustzone/normalDecryptKey.go:70 +0xd0 fp=0x40001b1890 sp=0x40001b1580 pc=0x696bc8
main.OptionsCommon.NormalDecryptKeyEvent(0x40001c2000, 0x7d9980, 0x40002c41c0, 0x40002e6600)
        /data/trustzone-agent/agent-ca/auth-module-trustzone/normalDecryptKey.go:40 +0x2c0 fp=0x40001b1a80 sp=0x40001b1890 pc=0x696a08
main.OptionsCommon.NormalDecryptKeyEvent-fm(0x7d9980, 0x40002c41c0, 0x40002e6600)
        /data/trustzone-agent/agent-ca/auth-module-trustzone/normalDecryptKey.go:21 +0x40 fp=0x40001b1ab0 sp=0x40001b1a80 pc=0x69cce8
net/http.HandlerFunc.ServeHTTP(0x40000120a0, 0x7d9980, 0x40002c41c0, 0x40002e6600)
        /usr/local/go/src/net/http/server.go:2007 +0x40 fp=0x40001b1ae0 sp=0x40001b1ab0 pc=0x61b8e8
github.com/gorilla/mux.(*Router).ServeHTTP(0x40002aa000, 0x7d9980, 0x40002c41c0, 0x40002e6400)
        /data/trustzone-agent/agent-ca/auth-module-trustzone/vendor/github.com/gorilla/mux/mux.go:210 +0xb4 fp=0x40001b1c10 sp=0x40001b1ae0 pc=0x690a3c
net/http.serverHandler.ServeHTTP(0x40002c4000, 0x7d9980, 0x40002c41c0, 0x40002e6400)
        /usr/local/go/src/net/http/server.go:2802 +0xc0 fp=0x40001b1c40 sp=0x40001b1c10 pc=0x61daa8
net/http.(*conn).serve(0x40002acf00, 0x7da2c0, 0x400006e500)
        /usr/local/go/src/net/http/server.go:1890 +0x714 fp=0x40001b1fc0 sp=0x40001b1c40 pc=0x61aadc
runtime.goexit()
        /usr/local/go/src/runtime/asm_arm64.s:1128 +0x4 fp=0x40001b1fc0 sp=0x40001b1fc0 pc=0x45997c
created by net/http.(*Server).Serve
        /usr/local/go/src/net/http/server.go:2928 +0x2ec

goroutine 1 [IO wait]:
internal/poll.runtime_pollWait(0xfffd74119108, 0x72, 0x0)
        /usr/local/go/src/runtime/netpoll.go:184 +0x44
internal/poll.(*pollDesc).wait(0x40002c6018, 0x72, 0x0, 0x0, 0x756e1d)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x38
internal/poll.(*pollDesc).waitRead(...)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Accept(0x40002c6000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_unix.go:384 +0x188
net.(*netFD).accept(0x40002c6000, 0x40001b5b38, 0x40001b5b98, 0x61a1b8)
        /usr/local/go/src/net/fd_unix.go:238 +0x2c
net.(*TCPListener).accept(0x400000e480, 0x63d9fe5f, 0x40001b5b78, 0x4378dc)
        /usr/local/go/src/net/tcpsock_posix.go:139 +0x2c
net.(*TCPListener).Accept(0x400000e480, 0x40001b5be0, 0x40001b5be8, 0x18, 0x4000000180)
        /usr/local/go/src/net/tcpsock.go:261 +0x3c
net/http.(*Server).Serve(0x40002c4000, 0x7d9700, 0x400000e480, 0x0, 0x0)
        /usr/local/go/src/net/http/server.go:2896 +0x220
net/http.(*Server).ListenAndServe(0x40002c4000, 0x40002c4000, 0x40001b5e08)
        /usr/local/go/src/net/http/server.go:2825 +0xac
net/http.ListenAndServe(...)
        /usr/local/go/src/net/http/server.go:3081
main.routerNormal(0x40001c2000)
        /data/trustzone-agent/agent-ca/auth-module-trustzone/tee-agent.go:140 +0x650
main.run(0x40001c2000)
        /data/trustzone-agent/agent-ca/auth-module-trustzone/tee-agent.go:111 +0x258
main.main()
        /data/trustzone-agent/agent-ca/auth-module-trustzone/tee-agent.go:68 +0x338

goroutine 13 [IO wait]:
internal/poll.runtime_pollWait(0xfffd74119038, 0x72, 0xffffffffffffffff)
        /usr/local/go/src/runtime/netpoll.go:184 +0x44
internal/poll.(*pollDesc).wait(0x40002c6618, 0x72, 0x0, 0x1, 0xffffffffffffffff)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x38
internal/poll.(*pollDesc).waitRead(...)
        /usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0x40002c6600, 0x400029f181, 0x1, 0x1, 0x0, 0x0, 0x0)
        /usr/local/go/src/internal/poll/fd_unix.go:169 +0x164
net.(*netFD).Read(0x40002c6600, 0x400029f181, 0x1, 0x1, 0x4000124768, 0x6158d4, 0x400006e290)
        /usr/local/go/src/net/fd_unix.go:202 +0x44
net.(*conn).Read(0x40000100c8, 0x400029f181, 0x1, 0x1, 0x0, 0x0, 0x0)
        /usr/local/go/src/net/net.go:184 +0x58
net/http.(*connReader).backgroundRead(0x400029f170)
        /usr/local/go/src/net/http/server.go:677 +0x50
created by net/http.(*connReader).startBackgroundRead
        /usr/local/go/src/net/http/server.go:673 +0xc8

问题查询

搜寻很多解决方案:

  • 有提出是go本身的问题,在搜索一些资料后发现目前似乎go的高版本解决了该问题,如果使用cgo就很可能出现类似问题,之前的go的dns库等很多借助cgo的库都出现过类似问题,似乎是glibc相关的内存栈分割和go本身存在差异导致的。1.18rc1 版本解决了该问题,https://github.com/golang/go/commit/a158382b1c9c0b95a7d41865a405736be6bc585f
  • 还有提出是因为协程调用发生的,提出互斥调用动态库,或者编译是使用一个核,GOMAXPROCS=1。

参考

  • https://blog.csdn.net/weixin_39510813/article/details/123407693
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值