最近需要在 go 中去调用 .so 库去完成一些事情,go 方面,利用 cgo 可以顺利的调用 .so 中的方法,但是有个问题是 go 没法捕获 .so 那边出现的异常。如果 .so 那边异常了,那么会带崩 go 程序,这不是我们想看到的。例如在 服务器应用中,某个异常的请求可能会把服务器进程给弄挂,这不是我们想看到的。

我们最好在可能会崩溃的地方进行异常捕获,可以做一层 wrapper,然后将错误信息传给 go 这边,让 go 去决定异常的处理方式,这里我写了一个简单的 Demo 进行验证。

首先我们写一个简单的 cpp 的库,做成 .so

  • foo 函数增加了 try catch,将异常信息通过 char* 返回给 go;
  • foo1 函数值抛出异常,不捕获;
// clib.h
#ifdef __cplusplus
extern "C" {
#endif #include <stdlib.h> typedef struct HANDLE_ERR {
char *data;
const char *pstrErr;
} HANDLE_ERR; HANDLE_ERR foo (const char *pstrArgs); char* foo1 (const char *pstrArgs); #ifdef __cplusplus
}
#endif // clib.cpp
#include <string.h>
#include <stdio.h>
#include <exception>
#include "clib.h" struct MyException : public std::exception
{
const char * what () const throw ()
{
return "C++ Exception";
}
}; HANDLE_ERR foo (const char *pstrArgs) {
HANDLE_ERR result = {0};
try {
if (pstrArgs == nullptr)
throw MyException();
result.data = "Hello word!";
} catch(MyException &e) {
result.data = nullptr;
result.pstrErr = strdup(e.what());
}
return result;
} char* foo1 (const char *pstrArgs) {
if (pstrArgs == nullptr)
throw "exception, nullptr";
char* data = "Hello word!";
return data;
}

我们用 g++ 来做成 .so,将上面的 cpp 做成 libclib.so 文件,供 go 来使用,下面是用 g++ 编译的指令命令。

g++ -c -fPIC clib.cpp
g++ -shared -fPIC -o libclib.so clib.o

在做好了 .so 后,我们用 go 来调用

  • passNullptr 传递一个空指针给 clib,clib 会抛出异常;
  • passNormal 传递正常的值
  • passNullptrNoException 传递空指针给 foo1 函数,foo1 没有捕获异常。
package main

// #cgo LDFLAGS: -L. -lclib
// #include <stdlib.h>
// #include "clib.h"
import "C" import (
"log"
"unsafe"
) func passNullptr() {
log.Println("1. passNullptr")
ret := C.foo(nil)
if ret.pstrErr != nil {
defer C.free(unsafe.Pointer(ret.pstrErr))
log.Println("clib error: ", C.GoString(ret.pstrErr))
} else {
log.Println("no error! from clib: ", C.GoString(ret.data))
}
log.Println("")
} func passNormal() {
log.Println("2. passNormal")
cArgs := C.CString("")
defer C.free(unsafe.Pointer(cArgs))
ret := C.foo(cArgs)
if ret.pstrErr != nil {
defer C.free(unsafe.Pointer(ret.pstrErr))
log.Println("clib error: ", C.GoString(ret.pstrErr))
} else {
log.Println("no error! from clib: ", C.GoString(ret.data))
}
log.Println("")
} func passNullptrNoException() {
log.Println("3. passNullptrNoException")
cArgs := C.CString("")
defer C.free(unsafe.Pointer(cArgs))
C.foo1(nil)
log.Println("")
} func main() {
passNullptr()
passNormal()
passNullptrNoException()
}

下面是输出的结果

2022/08/27 15:47:21 1. passNullptr
2022/08/27 15:47:21 clib error: C++ Exception
2022/08/27 15:47:21
2022/08/27 15:47:21 2. passNormal
2022/08/27 15:47:21 no error! from clib: Hello word!
2022/08/27 15:47:21
2022/08/27 15:47:21 3. passNullptrNoException
libc++abi: terminating with uncaught exception of type char const*
SIGABRT: abort
PC=0x7ff811758112 m=0 sigcode=0 goroutine 0 [idle]:
runtime: unknown pc 0x7ff811758112
stack: frame={sp:0x7ff7bfefed28, fp:0x0} stack=[0x7ff7bfe803e8,0x7ff7bfeff450)
...
...
exit status 2

我们可以看到,加了 try catch 后,clib 将 error 信息传递到了 go 侧,如果不 try catch 异常,clib 的异常会把 go 进行给带崩溃,所以在 go 调用 .so 的时候,最好做一层 wrapper 做一下异常处理。

[Golang] cgo 调用 .so 捕获异常问题的更多相关文章

  1. golang cgo 使用总结

    原文地址 CGO 提供了 golang 和 C 语言相互调用的机制.某些第三方库可能只有 C/C++ 的实现,完全用纯 golang 的实现可能工程浩大,这时候 CGO 就派上用场了.可以通 CGO ...

  2. Dapr Golang HTTP 调用

    Dapr Golang HTTP 调用 版本介绍 Go 版本:1.15 Dapr Go SKD 版本:0.11.1 工程结构 从上图可知,新建 3 个 Go 启动项目,cmd 为启动项目目录,其中 c ...

  3. Linux golang使用cgo调用C++标准库问题

    我们知道cgo无法直接调用c++方法,但是可以通过c包装c++方法,以达到使用的目的. C++中,我们经常会用到STL.在cgo中,如果要调用STL,需要作如下操作: //cgo LDFLAGS: - ...

  4. golang通过cgo调用lua

    目录 1.前期准备 2.测试go代码 3.完成的一个学习项目 4.总结 1.前期准备 1.第三方库:https://github.com/aarzilli/golua 2.下载lua源码:https: ...

  5. golang动态调用方法

    package main import ( "fmt" "reflect" ) type YourT1 struct { } func (y *YourT1) ...

  6. C/C++调用Golang 二

    C/C++调用Golang 二 <C/C++调用Golang 一>简单介绍了C/C++调用Golang的方法步骤,只涉及一个简单的函数调用.本文总结具体项目中的使用场景,将介绍三种较复杂的 ...

  7. Golang调用Python

    https://yq.aliyun.com/articles/117329 Python是时髦的机器学习御用开发语言,Golang是大红大紫的新时代后端开发语言.Python很适合让搞算法的写写模型, ...

  8. electron/nodejs实现调用golang函数

    https://www.jianshu.com/p/a3be0d206d4c 思路 golang 支持编译成c shared library, 也就是系统中常见的.so(windows下是dll)后缀 ...

  9. Golang 调用 Python 代码

    go 中的 cgo 模块可以让 go 无缝调用 c 或者 c++ 的代码,而 python 本身就是个 c 库,自然也可以由 cgo 直接调用,前提是指定正确的编译条件,如 Python.h 头文件( ...

随机推荐

  1. 如何优化PlantUML流程图(时序图)

    这篇文章用来介绍,如何画出好看的流程图. 1. 选择合适的组件 1.1 plantuml官方提供的组件 1.2 加载图片 1.2.1 加载本地图片 1.2.2 加载网络图片 1.2.3 图片资源 2. ...

  2. JMeter - 生成随机数/随机字符串/随机变量/随机日期

    1. Random - 随机数 1.1 作用 1.2 声明 1.3 例子 2. __RandomDate - 随机日期 2.1 作用 2.2 声明参数 2.3 例子 3. RandomString - ...

  3. 使用 Dapr JS SDK 让 Nest.js 集成 Dapr

    Dapr 是一个可移植的.事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的.无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架. Dapr 中文手册:ht ...

  4. Bika LIMS 开源LIMS集——实验室检验流程概述及主页、面板

    主页 主页左侧为功能入口菜单.右侧含待办提醒,中间为工作区. 工作区功能将主要工作页面置于首页,便于用户操作. Dashboard 面板 系统面板 包括待排定的实验任务.实验中的任务数.复核/审核中的 ...

  5. manjaro 安装后的基本配置

    第一步:设置官方镜像源 sudo pacman-mirrors -i -c China -m rank # 输入以上命令后会有弹出框,选择一个国内镜像(推荐 https://mirrors.ustc. ...

  6. gpg加解密异常

    在本地windows电脑和开发环境(linux) ,都不报错,但是在测试环境(linux) 上报错. 报错信息 org.bouncycastle.openpgp.PGPException: Excep ...

  7. 4-4 Spring Test

    Spring Test Ⅰ.主要解决的问题 使用SpringTest前 手动加载Sping配置 手动从Spring容器中获取对象 使用SpringTest后 只需要通过注解指定Spring配置类 在S ...

  8. day03_3_流程控制练习题

    # 流程控制练习题 # 一.编程题 1.实现一个课程名称和课程代号的转换器:输入下表中的课程代号,输出课程的名称.用户可以循环进行输入,如果输入0就退出系统.(**使用****switch +whil ...

  9. 如何手写一个js工具库?同时发布到npm上

    自从工作以来,写项目的时候经常需要手写一些方法和引入一些js库 JS基础又十分重要,于是就萌生出自己创建一个JS工具库并发布到npm上的想法 于是就创建了一个名为learnjts的项目,在空余时间也写 ...

  10. 21条最佳实践,全面保障 GitHub 使用安全

    GitHub 是开发人员工作流程中不可或缺的一部分.无论你去哪个企业或开发团队,GitHub 都以某种形式存在.它被超过8300万开发人员,400万个组织和托管超过2亿个存储库使用.GitHub 是世 ...