首页 > 其他分享 >[Golang] cgo 调用 .so 捕获异常问题

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

时间:2022-08-27 16:22:27浏览次数:53  
标签:char log cgo Golang Println clib go 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 <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 做一下异常处理。

标签:char,log,cgo,Golang,Println,clib,go,so
From: https://www.cnblogs.com/WAoyu/p/16630795.html

相关文章

  • day 22 JSONP及Axios
    JSONP及Axiosjsonp概述:JSONP是一种跨域解决方案,它主要是利用了script标签不受跨域影响的特性来完成对应的请求操作。实际上是一个get请求。什么叫跨域同源策略(属于浏览......
  • JSONP及Axios
    JSONP及Axiosjsonp概述:JSONP是一种跨域解决方案,它主要是利用了script标签不受跨域影响的特性来完成对应的请求操作。(默认是一个get请求。)什么叫跨域同源策略(属于浏览器......
  • IfcSolidOrShell
    IfcSolidOrShell类型定义iFCSolidShell提供了选择几何模型中的几何体(iFCSoledModel和子类型)或拓扑模型中的壳(IfcClosedShell)的选项。 IFC4中的新选择类型。  Enu......
  • 常用source
    KafkaSourcesa3.sources.r1.type=org.apache.flume.source.kafka.KafkaSourcea3.sources.r1.batchSize=5000a3.sources.r1.batchDurationMillis=2000a3.source......
  • QT使用HTTP下载来实现程序下载自动安装退出,同时读取JSON更新信息。
    最近在用QT开发一套免费的HelpDesk系统,参考了网上的方法,实现了程序自动下载更新和程序自动退出再安装新程序,为了感谢网页的无私分享,自己也特地分享给大家,希望可以帮助到大......
  • 基于Anacoda搭建虚拟环境cudnn6.0+cuda8.0+python3.6+tensorflow-gpu1.4.0
    !一定要查准cudnn,cuda,tensorflow-gpu对应的版本号再进行安装,且本文一切安装均在虚拟环境中完成。下文以笔者自己电脑为例,展开安装教程阐述(省略anaconda安装教程):1.查询电脑......
  • Solution - NOI 2022
    游记目前只有两个题题解(代码没有),啥时候数据出了我再来补剩下的。众数Solution有个题叫「POI2014」Couriers,这个题启示我们实际上问题等价于询问哪个数出现次数最多,最......
  • leetcode 205. Isomorphic Strings 同构字符串(简单)
    一、题目大意给定两个字符串s和t,判断它们是否是同构的。如果s中的字符可以按某种映射关系替换得到t,那么这两个字符串是同构的。每个出现的字符都应当映射到另一......
  • http跨域 【调试错误】Access to XMLHttpRequest at file:E590/ceshi.json from orig
    【调试错误】AccesstoXMLHttpRequestatfile:E590/ceshi.jsonfromoriginnull亲测有效!!!使用前后端分离的方式创建web项目的时候出现问题:这是因为ajax请求的对应......
  • IIS 【调试错误】Access to XMLHttpRequest at file:E590/ceshi.json from origin nul
    【调试错误】AccesstoXMLHttpRequestatfile:E590/ceshi.jsonfromoriginnull亲测有效!!!【调试错误】AccesstoXMLHttpRequestatfile:E590/ceshi.jsonfromorig......