bug诞生记——动态库加载错乱导致程序执行异常
大纲
- 背景
- 问题发生
- 问题猜测和分析过程
- 是不是编译了本工程中的其他代码
- 是不是有缓存
- 是不是编译了非本工程的文件
- 是不是调用了其他可执行文件
- 查看CMakefiles
- 分析源码
- 检查正在运行程序的动态库
- 解决方案
这个案例发生在我研究ROS 2的测试Demo时发生的。
整体现象是:修改了源码,编译也成功了,但是执行流程和没修改前一致,新代码的逻辑没有体现。
最后定位到“动态库加载错乱”这个根本的问题,方案也就呼之欲出。但是整个排查过程经历了若干假设和推导,还是值得记录下。
背景
在《Robot Operating System——Ubuntu上以二进制形式安装环境》这篇文章中,我们安装了二进制的ROS 2,并且通过下面的指令进行了测试
source /opt/ros/jazzy/setup.bash
ros2 run demo_nodes_cpp talker

后来为了研究它的一些源码,我从github上将demo_nodes_cpp的源码(https://github.com/ros2/demos/blob/rolling/demo_nodes_cpp)给下载到本地。执行编译后会生成build目录。在目录下会生成talker这类的可执行程序。然后我就用这些可执行程序进行编译结果测试。
问题发生
然后我看到demo_nodes_cpp/src/topics/talker_serialized_message.cpp源码时,有这么一段注释
// We know the size of the data to be sent, and thus can pre-allocate the// necessary memory to hold all the data.// This is specifically interesting to do here, because this means// no dynamic memory allocation has to be done down the stack.// If we don't allocate enough memory, the serialized message will be// dynamically allocated before sending it to the wire.auto message_header_length = 8u;auto message_payload_length = static_cast<size_t>(string_msg->data.size());serialized_msg_.reserve(message_header_length + message_payload_length);
它表达的是:这段代码去掉,程序也可以正常运行。因为rclcpp::SerializedMessage的空间会根据内容而动态分配。
然后我就去掉了这段代码,并新增了一个printf。
// We know the size of the data to be sent, and thus can pre-allocate the// necessary memory to hold all the data.// This is specifically interesting to do here, because this means// no dynamic memory allocation has to be done down the stack.// If we don't allocate enough memory, the serialized message will be// dynamically allocated before sending it to the wire.// auto message_header_length = 8u;// auto message_payload_length = static_cast<size_t>(string_msg->data.size());// serialized_msg_.reserve(message_header_length + message_payload_length);printf("serialized_msg_ allocate memory\n");
使用下面的指令编译后
colcon build --allow-overriding demo_nodes_cpp

再运行talker_serialized_message,发现“serialized_msg_ allocate memory”这句并没有输出。

问题猜测和分析过程
是不是编译了本工程中的其他代码
因为整个工程的编译模块我没细看,只能先盲猜一种最简单的原因,即:是不是编译了其他代码。
然后我搜索了上述输出中的关键字“serialized message”,发现源码文件中只有我修改的文件中才有。

这个猜测被排除!
是不是有缓存
我决定清掉build目录,重新执行编译。
中间也试过通过增加命令来在编译前清除缓存。
colcon build --cmake-clean-cache --cmake-clean-first --allow-overriding demo_nodes_cpp
很不幸,执行结果还是修改代码前的逻辑。
这个猜测排除!
是不是编译了非本工程的文件
这次测试比较暴力,直接将当前修改文件中printf的语法改错,看看编译是否报错。

报错了。
这个猜测排除!
将源文件还原成正确语法。
是不是调用了其他可执行文件
因为在《Robot Operating System——Ubuntu上以二进制形式安装环境》这篇文章中,我们使用安装的二进制文件,也运行成功了测试用例,所以怀疑通过源码编译的文件是不是在底层调用了之前通过二进制安装的另外一个环境的逻辑。
查看CMakefiles
在demo_nodes_cpp/build/demo_nodes_cpp/CMakeFiles目录下,有两个有关本例修改的目录。
- talker_serialized_message_library.dir
- talker_serialized_message.dir

通过名字可以看出来talker_serialized_message.dir对应于我们运行的可执行文件;talker_serialized_message_library.dir对应于某个库(是静态库还是动态库目前不明)。
我们将重点放在talker_serialized_message.dir上,因为我们运行的程序大概率就是通过它编译的。
在demo_nodes_cpp/build/demo_nodes_cpp/CMakeFiles/talker_serialized_message.dir/DependInfo.cmake文件中,我们看到一个比较陌生的文件node_main_talker_serialized_message.cpp
分析源码
# Consider dependencies only in project.
set(CMAKE_DEPENDS_IN_PROJECT_ONLY OFF)# The set of languages for which implicit dependencies are needed:
set(CMAKE_DEPENDS_LANGUAGES)# The set of dependency files which are needed:
set(CMAKE_DEPENDS_DEPENDENCY_FILES"/home/fangliang/demos/demo_nodes_cpp/build/demo_nodes_cpp/rclcpp_components/node_main_talker_serialized_message.cpp" "CMakeFiles/talker_serialized_message.dir/rclcpp_components/node_main_talker_serialized_message.cpp.o" "gcc" "CMakeFiles/talker_serialized_message.dir/rclcpp_components/node_main_talker_serialized_message.cpp.o.d")# Targets to which this target links which contain Fortran sources.
set(CMAKE_Fortran_TARGET_LINKED_INFO_FILES)# Targets to which this target links which contain Fortran sources.
set(CMAKE_Fortran_TARGET_FORWARD_LINKED_INFO_FILES)# Fortran module output directory.
set(CMAKE_Fortran_TARGET_MODULE_DIR "")
打开这个文件,我们发现它实际调用了libtalker_serialized_message_library.so来实现了整体功能。

这是一个非常重要的发现。它可以让我们将排查的方向指向动态库。
检查正在运行程序的动态库
我们先让程序运行起来

然后在另外一个终端中查找这个进程ID
ps -ef | grep talker_serialized_message

然后使用lsof来查看这个进程加载的是哪个目录下的动态库libtalker_serialized_message_library.so。
lsof -p 64759 | grep "libtalker_serialized_message_library.so"

可以发现它调用的是“/opt/ros/jazzy/lib/libtalker_serialized_message_library.so”,而不是我们编译的结果所在的目录(/home/fangliang/demos/demo_nodes_cpp/build/demo_nodes_cpp)。
这样就可以确定这个离奇的问题发生的原因了:
- 可执行程序调用了动态库来完成逻辑。
- 系统中有两份同名动态库。
- 可执行程序使用了错误路径下得动态库。
解决方案
解决方案也很简单,我们通过export LD_LIBRARY_PATH来修改优先级。
首先我们看下当前环境下的加载优先级(执行了source /opt/ros/jazzy/setup.bash导致环境是面向二进制ROS 2的)
echo $LD_LIBRARY_PATH
/opt/ros/jazzy/opt/rviz_ogre_vendor/lib:/opt/ros/jazzy/lib/x86_64-linux-gnu:/opt/ros/jazzy/opt/gz_math_vendor/lib:/opt/ros/jazzy/opt/gz_utils_vendor/lib:/opt/ros/jazzy/opt/gz_cmake_vendor/lib:/opt/ros/jazzy/lib
可以看到二进制安装的ROS 2环境位于高优先级。
我们只要将我们的路径提前即可
export LD_LIBRARY_PATH=/home/fangliang/demos/demo_nodes_cpp/build/demo_nodes_cpp:$LD_LIBRARY_PATH
然后执行程序,我们就看到我们修改的代码生效了。

相关文章:
bug诞生记——动态库加载错乱导致程序执行异常
大纲 背景问题发生问题猜测和分析过程是不是编译了本工程中的其他代码是不是有缓存是不是编译了非本工程的文件是不是调用了其他可执行文件查看CMakefiles分析源码检查正在运行程序的动态库 解决方案 这个案例发生在我研究ROS 2的测试Demo时发生的。 整体现象是:修改…...
Matlab演示三维坐标系旋转
function showTwo3DCoordinateSystemsWithAngleDifference() clear all close all % 第一个三维坐标系 origin1 [0 0 0]; x_axis1 [1 0 0]; y_axis1 [0 1 0]; z_axis1 [0 0 1];% 绕 x 轴旋转 30 度的旋转矩阵 theta_x 30 * pi / 180; rotation_matrix_x [1 0 0; 0 cos(th…...
redis的持久化机制以及集群模式
1.redis的持久化机制 内存数据库具有高速读写的优势,但由于数据存储在内存中,一旦服务器停止或崩溃,所有数据将会丢失。持久化机制的引入旨在将内存中的数据持久化到磁盘上,从而在服务器重启后能够恢复数据,提供更好的…...
【论文解读】大模型算法发展
一、简要介绍 论文研究了自深度学习出现以来,预训练语言模型的算法的改进速度。使用Wikitext和Penn Treebank上超过200个语言模型评估的数据集(2012-2023年),论文发现达到设定性能阈值所需的计算大约每8个月减半一次,95%置信区间约为5到14个月…...
WebApi配置Swagger、Serilog、NewtonsoftJson、Sqlsugar、依赖注入框架Autofac、MD5加密
文章目录 项目准备1、创建WebApi项目配置Swagger、Serilog、NewtonsoftJsonNewtonsoftJsonSwaggerSerilog 使用ORM框架SqlSugar创建Service类库构成MVC框架使用AutoFac进行依赖注入 创建用户登录接口添加用户时进行安全防护 项目准备 1、创建WebApi项目 配置Swagger、Serilog…...
【ffmpeg命令基础】视频选项讲解
文章目录 前言设置输出文件的帧数设置每秒播放的帧数设置输出视频的帧率示例1:更改输出视频的帧率示例2:将图像序列转换为视频 设置输入视频的帧率示例3:处理高帧率视频示例4:处理低帧率视频 同时设置输入和输出帧率示例5…...
使用uniapp开发小程序(基础篇)
本文章只介绍微信小程序的开发流程,如果需要了解其他平台的开发的流程的话,后续根据情况更新相应的文章,也可以根据uniapp官网的链接了解不同平台的开发流程 HBuilderX使用:https://uniapp.dcloud.net.cn/quickstart-hx.html 开发工具 开始…...
vue3【详解】组合式函数
什么是组合式函数? 利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数,用于实现逻辑复用,类似 react18 中的 hook 函数名称 – 以 use 开头,采用驼峰命名,如 useTitle参数 – 建议使用 toValue() 处理(…...
微服务实战系列之玩转Docker(六)
前言 刚进入大暑,“清凉不肯来,烈日不肯暮”,空调开到晚,还是满身汗。——碎碎念 我们知道,仓库可见于不同领域,比如粮食仓库、数据仓库。在容器领域,自然也有镜像仓库(registry&…...
Python题解Leetcode Hot100之动态规划
动态规划解题步骤-5部曲 确定dp数组(dp table)以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组 70. 爬楼梯 题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到…...
你了解GD32 MCU上下电要求吗
你了解GD32 MCU的上下电要求吗?MCU的上下电对于系统的稳定运行非常重要。 以GD32F30X为例,上电/掉电复位波形如如下图所示。 上电过程中,VDD/VDDA电压上电爬坡,当电压高于VPOR(上电复位电压)MCU开始启动&a…...
二、【Python】入门 - 【PyCharm】安装教程
往期博主文章分享文章: 【机器学习】专栏http://t.csdnimg.cn/sQBvw 目录 第一步:PyCharm下载 第二步:安装(点击安装包打开下图页面) 第三步:科学使用,请前往下载最新工具及教程:…...
2、程序设计语言基础知识
这一章节的内容在我们的软件设计师考试当中,考的题型比较固定,基本都是选择题,分值大概在2~4分左右。 而且考的还多是程序设计语言的一些基本语法,特别是这两年比较火的Python。 所以对于有一定要编程基础的即使本章的内容不学习&…...
ARM/Linux嵌入式面经(十八):TP-Link联洲
文章目录 虚拟内存,页表,copy on write面试题1:面试题2:面试题3:进程和线程的区别红黑树和b+树的应用红黑树的应用B+树的应用视频会议用了哪些协议1. H.323协议2. SIP协议(会话发起协议)3. WebRTC(网页实时通信)4. 其他协议io多路复用(select,poll,epoll)面试题li…...
解读vue3源码-响应式篇2
提示:看到我 请让我滚去学习 文章目录 vue3源码剖析reactivereactive使用proxy代理一个对象1.首先我们会走isObject(target)判断,我们reactive全家桶仅对对象类型有效(对象、数组和 Map、Set 这样的集合类型),而对 str…...
【测开能力提升-fastapi框架】fastapi能力提升 - 中间件与CORS
1. 中间件 1.1 介绍(ChatGPT抄的,大致可以理解) 一种机制,用于在处理请求和响应之前对其进行拦截、处理或修改。中间件可以在应用程序的请求处理管道中插入自定义逻辑,以实现一些通用的功能,如身份验证、…...
centos7安装es及简单使用
为了方便日后查看,简单记录下! 【启动es前,需要调整这个配置文件(/opt/elasticsearch-6.3.0/config/elasticsearch.yml)的两处ip地址,同时访问页面地址的ip:9200时,ip地址也对应修改】 【启动kibana前,需要调整这个配置文件(/opt/kibana-6.3.0/config/k…...
2024年自动驾驶SLAM面试题及答案(更新中)
自动驾驶中的SLAM(Simultaneous Localization and Mapping,即同步定位与地图构建)是关键技术,它能够让车辆在未知环境中进行自主定位和地图建构。秋招来临之际,相信大家都已经在忙碌的准备当中了,尤其是应届…...
HTML零基础自学笔记(上)-7.18
HTML零基础自学笔记(上) 参考:pink老师一、HTML, Javascript, CSS的关系是什么?二、什么是HTML?1、网页,网站的概念2、THML的基本概念3、THML的骨架标签/基本结构标签 三、HTML标签1、THML标签介绍2、常用标签图像标签ÿ…...
数学建模--图论与最短路径
目录 图论与最短路径问题 最短路径问题定义 常用的最短路径算法 Dijkstra算法 Floyd算法 Bellman-Ford算法 SPFA算法 应用实例 结论 延伸 如何在实际应用中优化Dijkstra算法以提高效率? 数据结构优化: 边的优化: 并行计算&…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...
