• [Golang] cgo 调用 .so 捕获异常问题


    最近需要在 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 
    
    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 
    #include 
    #include 
    #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 
    // #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 做一下异常处理。

  • 相关阅读:
    zf-node-process & linux
    常用面试/笔试开源小项目51~60
    C++ 类和对象 (5) 析构函数
    C#使用MX Component实现三菱PLC软元件数据采集的完整步骤(仿真)
    大学生抗击疫情感动人物最美逆行者网页设计作业 html抗疫专题网页设计 最美逆行者网页模板 致敬疫情感动人物网页设计制作
    想创建一个人名百度百科词条,但已经有相同重复的词条怎么办
    Qt消息对话框的使用
    MYSQL的主从复制
    Java 超新星开源项目 Solon v1.10.10 发布
    Linux 和 分区
  • 原文地址:https://www.cnblogs.com/WAoyu/p/16630795.html