一次使用LD_DEBUG定位问题的经历

news2024/11/28 2:29:16

在实际工作中,当遇到段错误,我们会很容易的想到这是非法访问内存导致的,比如访问了已经释放的内存,访问数据越界,尝试写没有写权限的内存等。使用gdb进行调试,查看出异常的调用栈,往往可以定位到问题原因。

但是有些时候,段错误问题的定位也没这么简单。本人在工作中就遇到了一个段错误的问题,问题原因不是那么直观,出问题的代码非常简单,直接按照常规的分析方法,很难分析出原因。往内存越界、内存没有权限这个方向分析无法定位问题。

当我们遇到这种问题的时候,没有思路的时候,往往会采用一种方式,就是把编译环境清空,完全重新再编译一遍。的确,很多时候如果我们的运行环境,有些库和可执行文件,如果不是在一个统一的环境下编译出来的,版本号对应不上,也会引起这样的问题。但是对于符号覆盖的情况,即使重新编译一遍,也无法解决问题。

除了重新编译一遍,我们还可以使用LD_DEBUG来查看调试信息,LD_DEBUG可以查看共享库的搜索和链接过程,也可以看到符号的绑定过程。

问题的实际原因:动态库中有同名的符号,在执行程序的时候出现了符号覆盖。

1问题复现

可执行文件直接依赖两个动态库,两个动态库有同名符号,这样编译可执行文件的时候无法编译通过。如果要复现这个问题,需要间接依赖。

如下图所示,liba.so和libb.so中有重名符号。libaa.so依赖liba.so,libbb.so依赖libb.so,可执行文件依赖libaa.so和libbb.so。可执行文件间接依赖liba.so和libb.so。

liba.so对于类test::example::Hello,在构造函数中申请了8字节的内存,在函数DoSame中对内存进行了写,在析构函数中释放了内存。
libb.solibb.so中的函数test::example::Hello::DoSame与liba.so中的函数重名。
libaa.so调用了liba.so中函数test::example::Hello::DoA
libbb.so调用了libb.so中的test::example::Hello::DoB和和test::example::Hello::DoSame
main在main函数中调用了libaa.so中的DoAA和libbb.so中的DoSame

main函数中调用了3个函数,分别为DoAA、DoBB、DoSame,调用关系如下图所示。

1.1liba.so

liba.h

#ifndef _LIB_A_H_
#define _LIB_A_H_

namespace test {
namespace example {
class Hello {
  public:
    Hello();
    ~Hello();
    void DoA();
    void DoSame();

    char *p = nullptr;
};
}
}

#endif

liba.cpp

#include <stdlib.h>
#include <iostream>
#include "liba.h"

namespace test {
namespace example {

Hello::Hello() {
  p = (char *)malloc(8);
  printf("p: %p, this: %p\n", p, this);
}

Hello::~Hello() {
  if (p) {
    std::cout << "free p\n";
    free(p);
  }
}

void Hello::DoA() {
  std::cout << "do a in liba.\n";
}

void Hello::DoSame() {
  std::cout << "do same in liba.\n";
  p[0] = 'a';
}
}
}

1.2libb.so

libb.h

#ifndef _LIB_B_H_
#define _LIB_B_H_

namespace test {
namespace example {
class Hello {
  public:
    void DoB();
    void DoSame();
};
};
};

#endif

libb.cpp

#include <iostream>
#include "libb.h"

namespace test {
namespace example {
void Hello::DoB() {
  std::cout << "do b in libb.\n";
}

void Hello::DoSame() {
  std::cout << "do same in libb.\n";
}
};
};

1.3libaa.so

libaa.h

void DoAA();

libaa.cpp

#include "libaa.h"
#include "liba.h"
#include <iostream>

void DoAA() {
  std::cout <<"do aa\n";
  test::example::Hello hello;
  hello.DoA();
}

1.4libbb.so

libbb.h

#include "libb.h"

void DoBB();
void DoSame();

libbb.cpp

#include <iostream>
#include "libbb.h"
#include "libb.h"

void DoBB() {
  std::cout << "do bb\n";
  test::example::Hello hello;
  hello.DoB();
}

void DoSame() {
  std::cout << "do same\n";
  test::example::Hello hello;
  hello.DoSame();
}

1.5main函数

#include <iostream>
#include <string>
#include "libaa.h"
#include "libbb.h"

int main() {
    DoAA();
    DoBB();
    DoSame();
    return 0;
}

使用如下命令进行编译:

g++ liba.cpp -fPIC --shared -o liba.so -g

g++ libb.cpp -fPIC --shared -o libb.so -g

g++ libbb.cpp libb.so -fPIC --shared -o libbb.so -g

g++ libaa.cpp liba.so -fPIC --shared -o libaa.so -g

g++ main.cpp libaa.so libbb.so -g

运行结果,如下,可以看到,出现了段错误。

使用gdb进行定位,在p[0]='a'这行代码出现了段错误。打印p的话,发现p是一个非法地址。

可以看到,按照我们的预期,main函数中调用DoSame是调用的libbb.so中的DoSame,而libbb.so中的DoSame是调用的libb.so中的test::example::Hello::DoSame。但是根据gdb中的栈可以看到,最终调用到了liba.so中的test::example::Hello::DoSame。

调用函数出现了错乱,与预期的不一致。

编译可执行文件的时候,如果有间接调用的函数,那么最终调用的函数不是在编译的时候确定的。而是在运行的时候动态绑定的。比如libbb.so中DoSame调用的test::example::Hello::DoSame,这个函数最终调用liba.so中的还是libb.so中的,是需要动态绑定的。

在启动a.out的时候,使用LD_DEBUG进行调试,如下命令,就可以看到运行是符号绑定的信息。

LD_DEBUG=bindings ./a.out

如下所示,DoSame最终调用到了libs.so中的函数,所以调用的函数与预期的不一致。

     41428:     binding file /home/wangyanlong/test/symboltest/libbb.so [0] to /home/wangyanlong/test/symboltest/liba.so [0]: normal symbol `_ZN4test7example5Hello6DoSameEv'

2符号优先级

2.1动态库中重复的符号

上一节中,编译main.cpp的时候使用的是下边的命令,libaa.so在libbb.so之前,这样编译的话,查找符号会优先使用liba.so中的符号。

g++ main.cpp  libaa.so libbb.so -g

如果修改两个库的顺序,libbb.so放在libss.so之前,那么就会绑定libb.so中的DoSame。

g++ main.cpp libbb.so libaa.so

2.2静态库和动态库重复符号

静态库中的符号是硬编到可执行文件中的,在绑定符号的时候肯定是可执行文件优先。如下所示,将liba.cpp编译成静态库。编译main.cpp的时候不管libaa.so、liba.a、libbb.so的先后顺序,test::example::Hello::DoSame都会绑定liba.so中的符号。

gcc liba.cpp -c

ar rcs liba.a liba.o

g++ libb.cpp -fPIC --shared -o libb.so -g

g++ libbb.cpp libb.so -fPIC --shared -o libbb.so -g

g++ libaa.cpp -fPIC --shared -o libaa.so -g

g++ main.cpp libbb.so libaa.so liba.a -g

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RTThread-Nano学习二-RT-Thread启动流程

一、简介 上一章&#xff0c;我们已经了解了如何通过MDK来移植RTT&#xff0c;不熟悉的可以看如下链接&#xff1a;RTThread-Nano学习一-基于MDK移植-CSDN博客本章我们就来继续了解一下&#xff0c;RTT的启动流程。 二、启动流程 官方给了一幅非常清晰的启动流程图&am…

11.学生成绩管理系统(Java项目基于SpringBoot + Vue)

目录 1.系统的受众说明 2 总体设计 2.1 需求概述 2.2 软件结构 3 模块设计 3.1 模块基本信息 3.2 功能概述 3.3 算法 3.4 模块处理逻辑 4 数据库设计 4.1 E-R图 4.2 表设计 4.2.1 管理员信息表 4.2.2 课程基本信息表 4.2.3 课程扩展信息表 4.2.4 专业信…

Cuda By Example - 8 (性能测量)

时间戳记录API 使用constant内存&#xff0c;究竟带来多少性能提升&#xff0c;如何尽可能精确的测量GPU完成某项任务所花的时间&#xff1f;CUDA提供了cudaEvent_t 以及 CUDA event API来做运行时间的测量。 cudaError_t cudaEventCreate(cudaEvent_t *event); cudaError_t c…

架构设计笔记-22-论文

1.论企业应用系统的数据持久层架构设计 2.论企业信息化规划的实施与应用 3.论企业应用系统的分层架构风格 4.论分布式存储架构系统设计 5.论云原生架构及其应用 6.论企业集成架构设计及应用 7.论数据湖技术及其应用 8.论系统安全架构设计及其应用 9.论企业集成平台的理解与应用…

【双指针算法】快乐数

1.题目解析 2.算法分析 由图可知&#xff0c;不管是最后可以变成1的还是不可以变成1的都相当于形成环了&#xff0c;只是成环处值不一样 问题转变成&#xff0c;判断链表是否有环 采用双指针&#xff0c;快慢指针算法 1.定义快慢指针2.慢指针每次向后移动一步&#xff0c;快…

ES-入门-javaApi-文档-新增-删除

新增指定索引的文档数据的代码如下&#xff1a; package com.atgulgu.es.test;import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.http.HttpHost; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexRe…

UNI VFX Missiles Explosions for Visual Effect Graph

Unity URP和HDRP的通用视觉效果 使用在视觉效果图中制作的高性能GPU粒子系统。 无需进入视觉效果图编辑器即可轻松自定义VFX。 使用(VFX)事件——一个游戏对象可存储多个效果,这些效果可通过C#或视觉脚本触发。 总共32个事件(不包括“停止”事件)。 ❓ 什么是(VFX)事件?…

STM32Cubemx 配置ADC(HAL库)

一、ADC几种模式 1、扫描模式&#xff1a; 使用STM32CUBEMX配置了多通道后&#xff0c;这一项默认开启且无法设置成关闭。这个模式就是自动扫描你开启的所有通道进行转换&#xff0c;直至转换完。例如你开启了CH0、CH1、CH2、CH3这四个通道&#xff0c;启动转换后ADC会自动将这…

动态规划原理及算法题(1)

课程规划会分为四个阶段进行&#xff1a; 1.题目解析 2.讲解算法原理(动态规划的原理) 3.编写代码 4.空间优化 1. 第 N 个泰波那契数&#xff08;easy&#xff09; 泰波那契数相当于斐波那契数的孪生兄弟&#xff0c;是它的加强版。 1.题目解析 2.讲解算法原理 如果用动态规…

Java中的一些名词概念

**函数式接口:** 概念&#xff1a;一个接口中的抽象方法只有一个&#xff0c;那么这个接口就是一个函数式接口。形参: 形参变量是**功能函数里的变量**&#xff0c;只有<u>在被调用的时候才分配内存单元</u>&#xff0c;<u>调用结束后立即释放</u>。…

Unity使用Git及GitHub进行项目管理

git: 工作区,暂存区(存放临时要存放的内容),代码仓库区1.初始化 git init 此时展开隐藏项目,会出现.git文件夹 2.减小项目体积 touch .gitignore命令 创建.gitignore文件夹 gitignore文件夹的内容 gitignore中添加一下内容 # This .gitignore file should be place…

Java项目-基于Springboot的应急救援物资管理系统项目(源码+说明).zip

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

Ubuntu20.04编译安卓aosp 15源码编译到模拟器运行

背景&#xff1a; aosp15也开始悄悄在各个手机厂商开始酝酿了&#xff0c;感叹时间很快&#xff0c;今天也准备针对aosp15进行一下源码环境的搭建&#xff0c;整体aosp15的搭建和13/14其实没啥大的差别&#xff0c;只不过在lunch目标这个地方确实很大不同&#xff0c;还有就是…

HCIP-HarmonyOS Application Developer 习题(十四)

&#xff08;多选&#xff09;1、HarmonyOs为应用提供丰富的Al(Artificial Intelligence)能力&#xff0c;支持开箱即用。下列哪些是它拥有的AI能力? A、通用文字识别 B、词性标注 C、实体识别 D、语音播报 答案&#xff1a;ABCD 分析&#xff1a; AI能力简介二维码生成根据开…

工业级三防平板在工厂极端环境下保障稳定运行

在现代工业环境中&#xff0c;尤其是在工厂车间&#xff0c;设备和技术的稳定性直接关系到生产效率与产品质量。然而&#xff0c;极端的工作条件常常给电子设备的使用带来了不小的挑战。为此&#xff0c;市场上出现了一种专为工业应用设计大尺寸手持三防平板电脑。这种设备以其…

2024年十大前沿图像分割模型汇总:工作机制、优点和缺点介绍

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

antd vue 输入框高亮设置关键字

<highlight-textareaplaceholder"请输入主诉"type"textarea"v-model"formModel.mainSuit":highlightKey"schema.componentProps.highlightKey"></highlight-textarea> 参考链接原生input&#xff0c;textarea demo地址 …

【前端】如何制作一个自己的网站(11)

接上文。 除了前面的颜色样式外&#xff0c;字体样式和文本样式也是网页设计中的重要组成部分。 合适的字体和文本排版&#xff0c;不仅可以使页面更加美观&#xff0c;也可以提升用户体验。接下来&#xff0c;我们先来看看CSS如何设置字体样式。 字体样式 同时设置了字体样…

经典算法整理(Go语言实现)

经典算法系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 第一章 回溯算法 第二章 贪心算法 第三章 动态规划 第四章 单调栈 第五章 图论 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可…

机器学习课程学习周报十七

机器学习课程学习周报十七 文章目录 机器学习课程学习周报十七摘要Abstract一、机器学习部分1. 变分推断/推理1.1 证据下界1.2 q ( z ) {q(z)} q(z)的选取 2. VAE2.1 Auto-Encoder的简单回顾2.2 为什么提出VAE2.3 VAE的数学原理 3. Diffusion Model的数学原理3.1 Training算法…