【go/方法记录】cgo静态库编译以及使用dlv定位cgo崩溃问题

目录

  • 说在前面
  • 文件树
  • 静态库编译
  • cgo使用
  • 崩溃模拟
  • 使用dlv定位崩溃
  • 参考

说在前面

  • 测试环境:WSL2
  • go版本:go version go1.23.1 linux/amd64
  • gcc版本:gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
  • cmake版本:3.22.1

文件树

├── buffer # go package
│   ├── buffer.go
│   ├── buffer_go.h
│   └── libbuffer.a
├── c # c/c++源代码
│   ├── CMakeLists.txt # cmake
│   ├── buffer # c/c++源代码
│   │   ├── buffer.h
│   │   ├── buffer_go.cpp
│   │   └── buffer_go.h
│   ├── lib # 静态库目录
│   │   └── libbuffer.a
│   └── main.cpp
└── main.go

静态库编译

  • 这部分和go无关,按照正常的静态库编译走就行,这里我使用cmake进行编译
  • buffer.h
    #ifndef __BUFFER_H__
    #define __BUFFER_H__
    #include <string>
    
    struct Buffer {
        std::string* s_;
    
        Buffer(int size) {
            this->s_ = new std::string(size, char('\0'));
        }
        ~Buffer() {
            delete this->s_;
        }
    
        int Size() const {
            return this->s_->size();
        }
        char* Data() {
            return (char*)this->s_->data();
        }
    };
    
    #endif
    
  • 然后我们需要对其进行封装,这部分可以参考这里
  • buffer_go.h
    #define DLLIMPORT
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    typedef struct Buffer_T Buffer_T;
    
    Buffer_T* NewBuffer(int size);
    void DeleteBuffer(Buffer_T* p);
    int BufferSize(Buffer_T* p);
    
    #ifdef __cplusplus
    }
    #endif
    
  • buffer_go.cpp
    #include "buffer.h"
    #include "buffer_go.h"
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    struct Buffer_T: Buffer {
        Buffer_T(int size): Buffer(size) {}
        ~Buffer_T() {}
    };
    
    DLLIMPORT Buffer_T* NewBuffer(int size) {
        auto p = new Buffer_T(size);
        return p;
    }
    
    DLLIMPORT void DeleteBuffer(Buffer_T* p) {
        delete p;
    }
    
    DLLIMPORT int BufferSize(Buffer_T* p) {
        return p->Size();
    }
    
    #ifdef __cplusplus
    }
    #endif
    
  • 然后就是cmake
    cmake_minimum_required(VERSION 3.2)
    project(Buffer)
    set(CMAKE_BUILD_TYPE "RELEASE")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
    
    # 设置编译后库文件目录
    set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
    
    include_directories(${PROJECT_SOURCE_DIR}/buffer)
    # 添加编译可执行文件
    aux_source_directory(${PROJECT_SOURCE_DIR}/buffer SRC)
    
    add_library(buffer STATIC ${SRC})
    add_executable(buffer_exe
            main.cpp
            )
    
    # 链接主程序
    target_link_libraries(buffer_exe
            PRIVATE
            buffer
            )
    
  • 执行编译
    cd ./c
    cmake .
    make
    
    动态库将生成在目录./c/lib

cgo使用

  • 首先将buffer_go.hlibbuffer.a拷贝到./buffer目录下,并创建buffer.go文件。注意,以下注释中的#include "buffer_go.h"import "C"不要有空行
  • buffer.go
    package buffer
    
    // #cgo CFLAGS: -I.
    // #cgo CXXFLAGS: -std=c++11
    // #cgo LDFLAGS: -L./ -lbuffer -lstdc++
    //
    // #include "buffer_go.h"
    import "C"
    
    type BufferT C.Buffer_T
    
    func NewBuffer(size int) *BufferT {
    	p := C.NewBuffer(C.int(size))
    	return (*BufferT)(p)
    }
    
    func DeleteBuffer(p *BufferT) {
    	C.DeleteBuffer((*C.Buffer_T)(p))
    }
    
    func BufferSize(p *BufferT) C.int {
    	return C.BufferSize((*C.Buffer_T)(p))
    }
    
  • 然后是main.go
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	b := buffer.NewBuffer(2)
    	fmt.Println(buffer.BufferSize(b))
    	buffer.DeleteBuffer(b)
    }
    
  • 执行程序输出
    ~/cgotest$ go run main.go
    2
    

崩溃模拟

  • 正常go中的崩溃,例如空指针调用等是可以通过recover处理的,例如

    func main() {
    
    	go func() {
    		defer func() {
    			if err := recover(); err != nil {
    				fmt.Println("err: ", string(debug.Stack()))
    			}
    		}()
    
    		time.Sleep(5 * time.Second)
    
    		var b uint32
    		var a uint32
    
    		_ = b / a
    	}()
    
    	var i int
    	for {
    		time.Sleep(time.Second)
    
    		i++
    		fmt.Println(i)
    	}
    }
    

    可以看到进程可以继续运行

    ~/cgotest$ go run main.go
    1
    2
    3
    4
    err:  goroutine 18 [running]:
    runtime/debug.Stack()
            /usr/local/go/src/runtime/debug/stack.go:26 +0x5e
    main.main.func1.1()
            /home/xx/cgotest/main.go:14 +0x2a
    panic({0x49cb60?, 0x54d840?})
            /usr/local/go/src/runtime/panic.go:785 +0x132
    main.main.func1()
            /home/xx/cgotest/main.go:23 +0x3f
    created by main.main in goroutine 1
            /home/xx/cgotest/main.go:11 +0x1a
    
    5
    6
    
  • 而对于cgo中的崩溃,目前go是没法进行recover的,会导致进程直接崩溃

    package main
    
    import (
    	"cgotest/cgotest/buffer"
    	"fmt"
    	"runtime/debug"
    	"time"
    )
    
    func main() {
    
    	go func() {
    		defer func() {
    			if err := recover(); err != nil {
    				fmt.Println("err: ", string(debug.Stack()))
    			}
    		}()
    
    		time.Sleep(5 * time.Second)
    		b := buffer.NewBuffer(2)
    		buffer.DeleteBuffer(b)
    
    		b = nil
    		fmt.Println(buffer.BufferSize(b))
    	}()
    
    	var i int
    	for {
    		time.Sleep(time.Second)
    
    		i++
    		fmt.Println(i)
    	}
    }
    
    ~/cgotest$ go run main.go
    1
    2
    3
    4
    SIGSEGV: segmentation violation
    PC=0x4930b4 m=5 sigcode=1 addr=0x0
    signal arrived during cgo execution
    
    goroutine 6 gp=0xc000007dc0 m=5 mp=0xc000100008 [syscall]:
    runtime.cgocall(0x492550, 0xc000076750)
    
    goroutine 6 gp=0xc000007dc0 m=5 mp=0xc000100008 [syscall]:
    runtime.cgocall(0x492550, 0xc000076750)
            /usr/local/go/src/runtime/cgocall.go:167 +0x4b fp=0xc000076728 sp=0xc0000766f0 pc=0x462f8b
    cgotest/cgotest/buffer._Cfunc_BufferSize(0x0)
            _cgo_gotypes.go:52 +0x47 fp=0xc000076750 sp=0xc000076728 pc=0x475b87
    main.main.func1.BufferSize.3(0x0)
            /home/xx/cgotest/buffer/buffer.go:22 +0x3b fp=0xc000076788 sp=0xc000076750 pc=0x4923fb
    cgotest/cgotest/buffer.BufferSize(...)
            /home/xx/cgotest/buffer/buffer.go:22
    main.main.func1()
            /home/xx/cgotest/main.go:29 +0x6c fp=0xc0000767e0 sp=0xc000076788 pc=0x49234c
    runtime.goexit({})
            /usr/local/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc0000767e8 sp=0xc0000767e0 pc=0x46e601
    created by main.main in goroutine 1
            /home/xx/cgotest/main.go:12 +0x1a
    
  • 可以看到进程退出并输出了堆栈信息

使用dlv定位崩溃

  • 虽然崩溃时的堆栈信息有标准输出,但是有时标准输出中的堆栈信息可能会被覆盖掉,少了最前面的信息,这个时候可以开启coredump并使用dlv来定位
  • 启用coredump
    ulimit -c unlimited
    GOTRACEBACK=crash go run main.go
    
    在进程崩溃后会生成coredump文件
  • 查看coredump文件目录
    ~/cgotest$ cat /proc/sys/kernel/core_pattern
    /mnt/wslg/dumps/core.%e
    
    可以看到文件生成在/mnt/wslg/dumps/
    ~/cgotest$ ll /mnt/wslg/dumps/
    total 6684
    -rw------- 1 le   le   83562496 Sep 21 16:04 core.main
    
  • 安装dlv
    go install github.com/go-delve/delve/cmd/dlv@latest
    
    可以在gopath文件夹下找到
    ~/cgotest$ /home/xx/go/bin/
    dlv          gopls        staticcheck
    
  • 使用
    # dlv core 二进制程序 coredump文件
    ~/go/bin/dlv core cgotest /mnt/wslg/dumps/core.main 
    
    结果如下
    ~/cgotest$ ~/go/bin/dlv core cgotest /mnt/wslg/dumps/core.main 
    Type 'help' for list of commands.
    (dlv) bt
     0  0x000000000046fde1 in runtime.raise
        at /usr/local/go/src/runtime/sys_linux_amd64.s:154
     1  0x000000000044b625 in runtime.dieFromSignal
        at /usr/local/go/src/runtime/signal_unix.go:942
     2  0x000000000044bc86 in runtime.sigfwdgo
        at /usr/local/go/src/runtime/signal_unix.go:1154
     3  0x000000000044a625 in runtime.sigtrampgo
        at /usr/local/go/src/runtime/signal_unix.go:432
     4  0x000000000046fde1 in runtime.raise
        at /usr/local/go/src/runtime/sys_linux_amd64.s:153
     5  0x000000000044b625 in runtime.dieFromSignal
        at /usr/local/go/src/runtime/signal_unix.go:942
     6  0x000000000044b1a6 in runtime.crash
        at /usr/local/go/src/runtime/signal_unix.go:1031
    Sending output to pager...
     0  0x000000000046fde1 in runtime.raise
        at /usr/local/go/src/runtime/sys_linux_amd64.s:154
     1  0x000000000044b625 in runtime.dieFromSignal
        at /usr/local/go/src/runtime/signal_unix.go:942
     2  0x000000000044bc86 in runtime.sigfwdgo
        at /usr/local/go/src/runtime/signal_unix.go:1154
     3  0x000000000044a625 in runtime.sigtrampgo
        at /usr/local/go/src/runtime/signal_unix.go:432
     4  0x000000000046fde1 in runtime.raise
        at /usr/local/go/src/runtime/sys_linux_amd64.s:153
     5  0x000000000044b625 in runtime.dieFromSignal
        at /usr/local/go/src/runtime/signal_unix.go:942
     6  0x000000000044b1a6 in runtime.crash
        at /usr/local/go/src/runtime/signal_unix.go:1031
     7  0x000000000044b1a6 in runtime.sighandler
        at /usr/local/go/src/runtime/signal_unix.go:806
     8  0x000000000044a726 in runtime.sigtrampgo
        at /usr/local/go/src/runtime/signal_unix.go:490
     9  0x00000000004930b4 in ???
        at ?:-1
    10  0x000000000049256b in C._cgo_a4c0d8419d5e_Cfunc_BufferSize
        at /tmp/go-build/buffer.cgo2.c:55
    11  0x000000000046e284 in runtime.asmcgocall
        at /usr/local/go/src/runtime/asm_amd64.s:923
    12  0x0000000000000000 in ???
        at ?:-1
    13  0x0000000000462fb5 in runtime.cgocall
        at /usr/local/go/src/runtime/cgocall.go:185
    14  0x0000000000475b87 in cgotest/cgotest/buffer._Cfunc_BufferSize
        at _cgo_gotypes.go:52
    15  0x00000000004923fb in main.main.func1.BufferSize.3
        at ./buffer/buffer.go:22
    16  0x0000000000492345 in cgotest/cgotest/buffer.BufferSize
        at ./buffer/buffer.go:22
    17  0x0000000000492345 in main.main.func1
        at ./main.go:29
    18  0x000000000046e601 in runtime.goexit
        at /usr/local/go/src/runtime/asm_amd64.s:1700
    

参考

  • dlv安装

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/881381.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【路径规划】 红嘴蓝鹊优化器:一种用于2D/3D无人机路径规划和工程设计问题的新型元启发式算法

摘要 本文提出了一种新型元启发式算法——红嘴蓝鹊优化器&#xff08;RBMO&#xff09;&#xff0c;用于解决2D和3D无人机路径规划以及复杂工程设计问题。RBMO灵感来源于红嘴蓝鹊的群体合作行为&#xff0c;包括搜索、追逐、捕猎和食物储藏。该算法通过模拟这些行为&#xff0…

prober found high clock drift,Linux服务器时间不能自动同步,导致服务器时间漂移解决办法。

文章目录 一、场景二、问题三、解决办法&#xff08;一&#xff09;给服务器添加访问网络能力&#xff08;二&#xff09;手动同步1. 检查有没有安装ntp2. 没有安装ntp则离线安装ntp2.1 下载安装包2.2 安装2.3 启动 ntp 3. 设置内部时钟源3.1 编辑/etc/ntp.conf3.1 重启ntp服务…

低代码平台后端搭建-阶段完结

前言 最近又要开始为跳槽做准备了&#xff0c;发现还是写博客学的效率高点&#xff0c;在总结其他技术栈之前准备先把这个专题小完结一波。在这一篇中我又试着添加了一些实际项目中可能会用到的功能点&#xff0c;用来验证这个平台的扩展性&#xff0c;以及总结一些学过的知识。…

【C++】关键字auto详解

&#x1f984;个人主页:小米里的大麦-CSDN博客 &#x1f38f;所属专栏:C_小米里的大麦的博客-CSDN博客 &#x1f381;代码托管:C: 探索C编程精髓&#xff0c;打造高效代码仓库 (gitee.com) ⚙️操作环境:Visual Studio 2022 目录 一、前言 二、类型别名思考 三、auto简介 四…

python 运行其他命令行工具,实时打印输出内容

起因&#xff0c; 目的: python 运行一个命令&#xff0c;最简洁的写法是: import os # 转换视频格式。 cmd "ffmpeg -i a1.ts -c copy a1.mp4"os.system(cmd)问题&#xff1a; 如果上面的视频比较大&#xff0c;需要运行很长时间&#xff0c;那么感觉就像是卡住…

向日葵和这三款远程控制神器,让你轻松掌控一切!

向日葵远程控制&#xff0c;作为科技控们的最佳良伴&#xff0c;一定是我们居家、办公必备的神器啦&#xff01;别看咱们工作、学习有时候烦得心都碎成了二八瓣&#xff0c;但有了向日葵远程控制&#xff0c;咱们的效率绝对能飞起来&#xff01;今天&#xff0c;咱们就一起走进…

C++11 lambda表达式

前言 上几期我们介绍了类的新功能&#xff0c;右值引用、完美转发语法特性&#xff0c;本期继续介绍C11的新语法特性&#xff0c;即lambda表达式&#xff01; 目录 前言 lambda表达式 lambda的引入 什么是lambda 表达式 lambda表达式的语法 捕捉列表说明 lambda的底层…

卡西欧相机SD卡格式化后数据恢复指南

在数字摄影时代&#xff0c;卡西欧相机以其卓越的性能和便携性成为了众多摄影爱好者的首选。然而&#xff0c;随着拍摄量的增加&#xff0c;SD卡中的数据管理变得尤为重要。不幸的是&#xff0c;有时我们可能会因为操作失误或系统故障而将SD卡格式化&#xff0c;导致珍贵的照片…

Linux笔记---简单指令

1. 使用的环境 博主使用的是华为云服务器xshell终端的方式学习的&#xff0c;因为据说这样的方式比较接近以后的工作环境。 其中云服务器安装的是Ubuntu操作系统(以Linux为内核&#xff0c;适合新手学习Linux的一个版本) 这里的云服务器不一定使用华为的&#xff0c;但是我在…

后台数据管理系统 - 项目架构设计-Vue3+axios+Element-plus(0920)

十三、文章分类页面 - [element-plus 表格] Git仓库&#xff1a;https://gitee.com/msyycn/vue3-hei-ma.git 基本架子 - PageContainer 功能需求说明&#xff1a; 基本架子-PageContainer封装文章分类渲染 & loading处理文章分类添加编辑[element-plus弹层]文章分类删除…

win7自带壁纸丢失主题丢失

有时候盗版破解或者其他美化工具会导致win7自带的壁纸丢失&#xff0c;从个性化管理里面无法恢复原始的壁纸&#xff08;如下图&#xff09;&#xff0c;但是由于工作原因公司的电脑又不方便设置第三方的壁纸&#xff0c;所以找了一下解决方案。 经典问题&#xff0c;百度找到的…

用户态缓存:高效数据交互与性能优化

目录 1. 用户态缓存区工作背景 1.1 为什么每条连接都需要读写缓存区 1.1.1 读缓存区&#xff08;Read Buffer&#xff09; 1.1.2 写缓存区&#xff08;Write Buffer&#xff09; 1.2 用户态缓存区的工作流程 1.3 用户态缓存区的重要性 2. UDP 和 TCP 的设计差异 2.1 UD…

机器翻译与数据集_by《李沐:动手学深度学习v2》pytorch版

系列文章目录 文章目录 系列文章目录介绍机器翻译下载和预处理数据集词元化词表加载数据集训练模型对上述代码中出现的Vocab进行总体解释和逐行解释使用场景 小结练习答案1. num_examples 参数对词表大小的影响2. 对于没有单词边界的语言&#xff0c;单词级词元化的有效性 介绍…

关于 Visual Studio Code 如何插入自定义快捷方式

第一步&#xff1a;打开控制面板&#xff0c;也可以使用快捷键ctrlshiftp 然后点击命令面板 第二步&#xff1a;输入snippets搜索&#xff0c;选择配置用户代码片段 第三步&#xff1a;选择新建全局代码片段文件&#xff0c;然后输入文件名&#xff0c;这里我因为创建的是vue的…

解决uniapp开发的app,手机预览,上下滑动页面,页面出现拉伸,抖动的效果问题,

在pages.json文件里“globalStyle”下面的"app-plus"里加入"bounce": "none"即可 "app-plus": { "bounce": "none", //关闭窗口回弹效果 }

2024年华为杯数学建模研赛(C题) 建模解析| 磁芯损耗建模 | 小鹿学长带队指引全代码文章与思路

我是鹿鹿学长&#xff0c;就读于上海交通大学&#xff0c;截至目前已经帮2000人完成了建模与思路的构建的处理了&#xff5e; 本篇文章是鹿鹿学长经过深度思考&#xff0c;独辟蹊径&#xff0c;实现综合建模。独创复杂系统视角&#xff0c;帮助你解决研赛的难关呀。 完整内容可…

2024华为杯研究生数学建模竞赛(研赛)选题建议+初步分析

提示&#xff1a;C君认为的难度&#xff1a;DE<C<F&#xff0c;开放度&#xff1a;CDE>F。 华为专项的题目&#xff08;A、B题&#xff09;暂不进行选题分析&#xff0c;不太建议大多数同学选择&#xff0c;对自己专业技能有很大自信的可以选择华为专项的题目。后续会…

Mysql_使用简介

课 程 推 荐我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448;入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448;虚 拟 环 境 搭 建 &#xff1a;&#x1…

2024华为杯研赛D题保姆级教程思路分析+教程

2024年中国研究生数学建模竞赛D题保姆级教程思路分析 D题&#xff1a;大数据驱动的地理综合问题&#xff08;数学分析&#xff0c;统计学&#xff09; 关键词&#xff1a;地理、气候、统计&#xff08;细致到此题&#xff1a;统计指标、统计模型、统计结果解释&#xff09; …

Linux通过yum安装Docker

目录 一、安装环境 1.1. 旧的docker包卸载 1.2. 安装常规环境包 1.3. 设置存储库 二、安装Docker社区版 三、解决拉取镜像失败 3.1. 创建文件目录/etc/docker 3.2. 写入镜像配置 https://docs.docker.com/engine/install/centos/ 检测操作系统版本&#xff0c;我操作的…