CSAPP第三版运行时打桩Segmentation fault

2023-11-09

CSAPP第三版7.13.3节提到了运行时打桩机制,它可以在运行时将程序中对共享库函数的调用进行截获,替换为执行自己的代码。这个机制基于动态链接器的LD_PRELOAD环境变量。如果LD_PRELOAD环境变量被设置为一个共享路径名的列表(以空格或分号分隔),那么当加载和执行一个程序,需要解析未定义的引用时,动态链接器(ld-linux.so)会先搜索LD_PRELOAD库,然后才搜索任何其他的库。有了这个机制,当加载和执行任意可执行文件时,可以对共享库中的任何函数打桩,包括libc.so。
书中给出的自己编写的malloc和free的包装函数如下。在每个包装函数中,对dlsym的调用返回指向目标libc函数的指针。然后包装函数调用目标函数,打印追踪记录,再返回。

#ifdef RUNTIME
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

void *malloc(size_t size)
{
    void *(*mallocp)(size_t size);
    char *error;

    mallocp = dlsym(RTLD_NEXT, "malloc");
    if ((error = dlerror()) != NULL)
    {
        fputs(error, stderr);
        exit(1);
    }
    char *ptr = mallocp(size);
    printf("malloc(%d) = %p\n", (int)size, ptr);
    return ptr;
}

void free(void *ptr)
{
    void (*freep)(void *) = NULL;
    char *error;

    if (!ptr)
        return;

    freep = dlsym(RTLD_NEXT, "free");
    if ((error = dlerror()) != NULL)
    {
        fputs(error, stderr);
        exit(1);
    }
    freep(ptr);
    printf("free(%p)\n", ptr);
}
#endif

其编译指令为:

gcc –DRUNTIME –shared –fpic –o mymalloc.so mymalloc.c –ldl

主程序代码如下:

#include <stdio.h>
#include <malloc.h>

int main(int argc, char **argv[])
{
    int *p = malloc(32);
    free(p);
    return 0;
}

其编译指令为:

gcc –o intr int.c

则在bash中使用运行时打桩机制运行该程序的指令如下:

LD_PRELOAD=”./mymalloc.so” ./intr

很不幸,这样做会出错(至少在我的机器上),错误如下:

Segmentation fault (core dumped)

发生了一个段错误,我们使用gdb来看看出了什么问题(先要加上-g选项使用gcc对库和程序重新编译,为了区分后面修改过的代码,我把包装函数的代码的文件名改成了badmalloc.c,动态库的名字改成了badmalloc.so):

gdb ./intr

设置LD_PRELOAD环境变量:

(gdb) set environment LD_PRELOAD=./badmalloc.so

直接开始执行程序:

(gdb) r

再次出现段错误:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff78591c3 in vfprintf () from /lib/x86_64-linux-gnu/libc.so.6

看看调用堆栈:

(gdb) bt

你会得到一个很长很长调用堆栈(反正我翻到了两万多行还没结束):

#0  0x00007ffff78591c3 in vfprintf () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007ffff7861849 in printf () from /lib/x86_64-linux-gnu/libc.so.6
#2  0x00007ffff7bd582e in malloc (size=1024) at badmalloc.c:19
#3  0x00007ffff7879185 in _IO_file_doallocate () from /lib/x86_64-linux-gnu/libc.so.6
#4  0x00007ffff78874c4 in _IO_doallocbuf () from /lib/x86_64-linux-gnu/libc.so.6
#5  0x00007ffff7886828 in _IO_file_overflow () from /lib/x86_64-linux-gnu/libc.so.6
#6  0x00007ffff78851bd in _IO_file_xsputn () from /lib/x86_64-linux-gnu/libc.so.6
#7  0x00007ffff7859201 in vfprintf () from /lib/x86_64-linux-gnu/libc.so.6
#8  0x00007ffff7861849 in printf () from /lib/x86_64-linux-gnu/libc.so.6
#9  0x00007ffff7bd582e in malloc (size=1024) at badmalloc.c:19
#10 0x00007ffff7879185 in _IO_file_doallocate () from /lib/x86_64-linux-gnu/libc.so.6
#11 0x00007ffff78874c4 in _IO_doallocbuf () from /lib/x86_64-linux-gnu/libc.so.6
#12 0x00007ffff7886828 in _IO_file_overflow () from /lib/x86_64-linux-gnu/libc.so.6
#13 0x00007ffff78851bd in _IO_file_xsputn () from /lib/x86_64-linux-gnu/libc.so.6
#14 0x00007ffff7859201 in vfprintf () from /lib/x86_64-linux-gnu/libc.so.6
#15 0x00007ffff7861849 in printf () from /lib/x86_64-linux-gnu/libc.so.6
#16 0x00007ffff7bd582e in malloc (size=1024) at badmalloc.c:19
#17 0x00007ffff7879185 in _IO_file_doallocate () from /lib/x86_64-linux-gnu/libc.so.6
#18 0x00007ffff78874c4 in _IO_doallocbuf () from /lib/x86_64-linux-gnu/libc.so.6
#19 0x00007ffff7886828 in _IO_file_overflow () from /lib/x86_64-linux-gnu/libc.so.6
#20 0x00007ffff78851bd in _IO_file_xsputn () from /lib/x86_64-linux-gnu/libc.so.6
#21 0x00007ffff7859201 in vfprintf () from /lib/x86_64-linux-gnu/libc.so.6
#22 0x00007ffff7861849 in printf () from /lib/x86_64-linux-gnu/libc.so.6
#23 0x00007ffff7bd582e in malloc (size=1024) at badmalloc.c:19
#24 0x00007ffff7879185 in _IO_file_doallocate () from /lib/x86_64-linux-gnu/libc.so.6
#25 0x00007ffff78874c4 in _IO_doallocbuf () from /lib/x86_64-linux-gnu/libc.so.6
---Type <return> to continue, or q <return> to quit---

需要注意,从#9到#2(调用关系要倒着看):
malloc->printf->vfprintf->_IO_file_xsputn->_IO_file_overflow->_IO_doallocbuf->_IO_file_doallocate->malloc
我们的malloc函数中调用了printf函数,printf函数又调用了我们的malloc函数,malloc函数又会调用printf函数……这产生了一个调用死循环,调用层次足够深,栈就溢出了。
那么如何打破这个死循环呢?首先要尽量避免在自己写的malloc函数中调用其他标准库函数,毕竟不清楚标准库函数的内部实现机制。但是为了输出一些信息,printf函数还是要保留的,那么怎么办呢?首先考虑单线程的情况,如果在我们自己写的malloc函数中发生了循环调用自己malloc的情况,唯一的可能就是printf调用了malloc。我们可以设置一个静态计数变量count,每次完成执行malloc函数后将count清零,每次进入malloc函数后count自增1,如果count=1,说明现在调用栈上只有对自定义malloc函数的一次调用,这时可以调用printf输出信息;如果count=2,说明此时调用栈上对malloc函数发生了第二次调用,即一个malloc函数还没有执行完,就又进行了一次malloc函数调用,我们认为这个问题出在printf上,此时我们就不再调用printf了。那么多线程情况呢?这个使用__thread修饰符将静态变量设置为thread local的就可以了。最后的malloc函数代码如下:

void *malloc(size_t size)
{
    static __thread int print_times = 0;
    print_times++;
    void *(*mallocp)(size_t size);
    char *error;

    mallocp = dlsym(RTLD_NEXT, "malloc");
    if ((error = dlerror()) != NULL)
    {
        fputs(error, stderr);
        exit(1);
    }
    char *ptr = mallocp(size);
    if (print_times == 1)
    {
        printf("malloc(%d) = %p\n", (int)size, ptr);
    }
    print_times = 0;
    return ptr;
}

然后我将int.c改成了这样,验证printf是否会调用malloc:

#include <stdio.h>
#include <malloc.h>

int main(int argc, char **argv[])
{
    printf("hello, world!\n");
    return 0;
}

程序输出如下:

malloc(1024) = 0x22b0010
free(0x22b0420)
hello, world!

也就是说printf确实是调用了malloc的。
实际上dlsym、dlerror和fputs这些函数也是有可能调用了malloc函数的,但是程序正确运行了,说明在这种场景下这些函数没有调用malloc函数,在其他场景下是否会调用malloc函数就不一定了。为了简单起见,没有进行更多的修改。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CSAPP第三版运行时打桩Segmentation fault 的相关文章

  • 从变量使用 OLE DB 源命令的 EzAPI 等效项是什么?

    tl dr 使用 来自变量的 SQL 命令 数据访问模式的 OLE DB 源并分配变量的 EzAPI 代码是什么 Preamble 每月一次 我们需要使用生产数据的子集刷新我们的公共测试站点 我们已确定 根据我们的需求 SSIS 解决方案最
  • 创建动态对象

    如何动态创建对象 string columnNames EmpName EmpID PhoneNo List
  • 获取在 Unity 中实现接口的所有类型

    如果您只想知道解决方案 请跳至更新 我有一个应用程序 它使用以下代码来获取并运行许多工作方法 var type typeof IJob var types AppDomain CurrentDomain GetAssemblies Sele
  • 如何将带有自定义标头的任意 JSON 数据发送到 REST 服务器?

    TL DR 如何将 JSON 字符串发送到带有 auth 标头的 REST 主机 我尝试了 3 种不同的方法 发现一种适用于匿名类型 为什么我不能使用匿名类型 我需要设置一个名为 Group Name 的变量 并且连字符不是有效的 C 标识
  • 检查文件是真实文件还是符号链接

    有没有办法使用 C 来判断文件是真实文件还是符号链接 我已经挖过了MSDN W32 文档 https learn microsoft com en us windows win32 fileio file management functi
  • 如何使用 VB.NET 或 C#.NET 代码从 yahoo 邮件 ID 发送邮件

    我想从我的 yahoomail Id 发送邮件 如何使用 VB NET 或 C NET 代码从 yahoo mail Id 发送邮件 需要善意的帮助 提前谢谢 西瓦库马尔 以下是一些制作基本 html 电子邮件消息的示例 http help
  • SQL 选择与带有通配符的 URL 匹配的行

    我在数据库中有一个表 其中一列包含一个 URL 例如http example com users http example com users 轮廓 我得到了一个 URL 例如http example com users 234 profi
  • 要实现 XML 可序列化,从 ICollection 继承的类型必须具有 Add 的实现

    我有来自现有项目的 CSLA 1 x 框架 对象 我试图在新的 Net 4 0 项目中使用它 这些对象正在生产中使用 如果没有 2 组对象 我确实无法将它们转换为 2 x 或 EF 在我的 c webservice 中 当我尝试运行它时 我
  • 为什么编译器不对同一翻译单元中的 ODR 违规发出警告

    在同一个翻译单元中 ODR 问题很容易诊断 那么为什么编译器不会针对同一翻译单元中的 ODR 违规发出警告呢 例如在下面的代码中https wandbox org permlink I0iyGdyw9ynRgny6 https wandbo
  • const int 列表而不是 enum

    我开始研究大型 C 代码库 并发现使用带有多个 const ints 字段的静态类 这个类的行为与枚举完全一样 我想将类转换为实际的枚举 但权力被拒绝 我想转换它的主要原因是这样我可以将枚举作为数据类型而不是 int 这对可读性有很大帮助
  • 当 MSB 位等于 0 时如何以十六进制格式打印它们

    我需要使用打印变量HEX格式 问题是当我的变量很小时 MSB 等于 0 因此不会打印它们 ex uint16 t var 10 0x000A h gt 我需要打印 000A 但无论我做什么它总是打印 A 我怎样才能让它发挥作用 您可以添加前
  • Time 方法在另一个线程中执行并在超时时中止

    您好 我正在尝试异步运行方法 以便计算持续时间并在超过超时时取消该方法 我尝试使用异步和等待来实现这一点 但没有运气 也许我过度设计了这个 任何输入都会受到赞赏 应该注意的是 我无法更改接口 TheirInterface 因此得名 到目前为
  • DateTimeFormat.AbbreviatedMonthNames 在月份名称末尾添加一个点

    昨晚 我们将 Web 服务层从物理 Windows 2008 r2 迁移到虚拟 Windows 2012 我们的日志中收到大量有关 DateTime 无效格式的事件 这很奇怪 因为我们仔细检查了区域设置 长话短说 CultureInfo G
  • CGAL:如何有效计算多面体的面面积?

    我有一个多面体 其面是三角形 我知道在 CGAL 中 Triangle 3 类提供了 squared area 方法 通过它我们可以计算三角形的面积 有什么方法可以将其应用到多面体方面吗 或者关于如何计算每个面的面积有什么想法吗 这是一个例
  • 从多页 tiff 中提取帧 - C#

    有一个多页 tiff 我想从此 Tiff 文件中提取第 n 页 帧 n 并保存它 如果我的多页 tiff 有 3 帧 在我提取一页 帧后 我想留下 1 张图像有 2 页 帧 并且 1 张图像只有 1 页 帧 下面是一些代码 用于将多帧 ti
  • 什么时候适合在 C++ 中使用 static(在未命名的命名空间上)?

    我一整天都在阅读有关未命名命名空间的文章 大多数文章都解释了何时应该在 static 关键字上使用未命名命名空间 但我仍然有一个大问题什么时候适合使用静态 毕竟它还没有完全弃用 那么带有静态函数的头文件我现在应该将它们放入未命名的命名空间中
  • 使用 C++20 概念避免 std::function

    过去 当我想要回调作为函数参数时 我通常决定使用std function 在极少数情况下 我绝对从不使用捕获 我使用了typedef改为函数声明 因此 通常我的带有回调参数的声明看起来像这样 struct Socket void on re
  • 将base64字符串转换为图像c#时出错

    我想在我的网页上显示图像 并单击应该下载的链接按钮 存储的图像文件以二进制格式存储在db中 将 base64 字符串转换为图像时显示错误 详细信息如下 帮助我找到合适的解决方案 谢谢 Error Code protected void Pa
  • 在实体框架中比较日期的最佳方法

    我在实体框架的 where 子句中使用日期并收到以下错误 这是由于以下代码 var entity dbContext MyTable Where w gt w PId 3 w CreatedOn Date mydate Date First
  • qt 如何知道按钮被点击?

    我正在尝试编写一个程序 用声音进行一些操作 我的问题是我有 3 个播放按钮和 3 个标签 我希望无论我单击 播放 按钮 都应该播放按钮附近标签中名称的声音 我有一个没有任何参数的播放插槽 那么 如何分别连接到每个播放按钮和每个标签呢 实际上

随机推荐

  • angular 代理http到https

    api target https www XXXX com changeOrigin true public target https www XXXX com changeOrigin true
  • uniapp switch按钮的使用

    switch使用官方文档 https uniapp dcloud io component switch 想要改变switch按钮的大小
  • Cloudera CDH 5.1版本的Hive与LDAP-2.4.44集成

    文章目录 0 没集成之前测试 1 安装LDAP 2 4 44 2 增加组织 3 添加用户 4 CDH配置LDAP 5 beeline测试1 5 beeline测试2 0 没集成之前测试 可以看到没有输入用户密码可以登录 1 安装LDAP 2
  • OpenGL学习笔记(十)-几何着色器-实例化

    参考网址 LearnOpenGL 中文版 4 7 几何着色器 4 7 1 基本概念 1 顶点和片段着色器之间有一个可选的几何着色器 几何着色器的输入是一个图元 如点或三角形 的一组顶点 顶点发送到下一着色器之前可对它们随意变换 将顶点变换为
  • 【Web Crawler】Python 的 urllib.request 用于 HTTP 请求

    如果您需要使用 Python 发出 HTTP 请求 那么您可能会发现自己被引导至 brilliantrequests库 尽管它是一个很棒的库 但您可能已经注意到它并不是 Python 的内置部分 如果您出于某种原因更喜欢限制依赖项并坚持使用
  • qt 中lineEdit->setText()输出double

    在qt中需要将获取到的double 值在ui界面上显示出来 便于观察 但是lineEdit控件的setText 要求的参数是string 所以我们先要进行转化 将double 转化为string QString QString number
  • 计算方法实验(二):龙贝格积分法

    Romberg积分法数学原理 利用复化梯形求积公式 复化辛普生求积公式 复化柯特斯求积公式的误差估计式计算积分 a b f x
  • 有效的数独

    LeetCode 之 有效的数独 判断一个 9x9 的数独是否有效 只需要根据以下规则 验证已经填入的数字是否有效即可 数字 1 9 在每一行只能出现一次 数字 1 9 在每一列只能出现一次 数字 1 9 在每一个以粗实线分隔的 3x3 宫
  • python机器学习-乳腺癌细胞挖掘(基于真实美国临床数据)

    随着人们生活水平提高 大家不仅关注如何生活 而且关注如何生活得更好 在这个背景下 精准治疗和预测诊断成为当今热门话题 据权威医学资料统计 全球大约每13分钟就有一人死于乳腺癌 乳腺癌已成为威胁当代人健康的主要疾病之一 并且随着发病率的增加
  • Error mounting /dev/sr0 at /media/ VBox

    重新安装Linux映像 sudo apt get install reinstall linux image uname r
  • IBM WAS简介

    IBM WAS简介 IBM WAS 的全称是 IBM WebSphere Application Server 和 Weblogic 一样 是 当前主流的 App Server 应用服务器 之一 App Server 是运行 Java 企
  • DataWhale集成学习(下)——Task14 案例分析1幸福感预测

    目 录 背景介绍 数据信息 评价指标 案例 背景介绍 数据来源于国家官方的 中国综合社会调查 CGSS 文件中的调查结果中的数据 数据来源可靠可依赖 用139维的信息来预测其对幸福感的影响 数据信息 139维 8000余组 幸福感预测值为1
  • 【indemind双目惯性相机调试】sudo后找不到命令问题,环境变量问题

    问题1 报错 kanhao100 ubuntu x86 roslaunch imsee ros wrapper start launch RLException start launch is neither a launch file i
  • 深度学习_调参经验

    面对一个图像分类问题 可以有以下步骤 1 建立一个简单的CNN模型 一方面能够快速地run一个模型 以了解这个任务的难度 卷积层1 卷积核大小3 3 卷积核移动步长1 卷积核个数64 池化大小2 2 池化步长2 池化类型为最大池化 激活函数
  • leetCode热题46-51 解题代码,调试代码和思路

    前言 本文属于特定的六道题目题解和调试代码 正所谓磨刀不误砍柴功 下面我做这几篇文档对于涉及的题型或者数据结构的分析都很有帮助 贴出来仅供参考 1 69 x 的平方根 Easy 2022 12 28 101 2 22 括号生成 Medium
  • JSP核心标签库

    1 一般标签 在JSTL中 一般标签主要用在输出 设置变量值和错误处理等 这些是JSTL中使用最多的标签 1 计算一个表达式的值 然后把计算的结果输出到当前的JspWriter对象 调用的结果和Servlet中out println 语句效
  • linux 删除指定文件夹包含指定字符串的文件会把所有子文件夹包含的都删除

    需求就是在linux服务器上面删除 指定文件夹里面所有包含 delete 内容的文件 并且所有此文件夹里面的子文件夹查出来也要删除掉 使用以下脚本可以进行实现 grep r l delete data xargs rm rf 脚本说明 gr
  • 机器学习-fp16相乘

    1位符号位 5位指数位 10位尾数位 共16位 内存占2个字节 具体fp16表示法可以参照 机器学习 fp16表示 运算步骤 检查操作数中是否有0 Inf NaN NaN a Nan Inf 0 Nan Inf 0 Nan Inf a In
  • UTSim:无人机空中交通集成、控制和通信的框架和模拟器

    计算机仿真资源的可用性有利于无人机的开发和在现实应用中的集成 因为它们降低了成本 风险 开发和测试时间 并提高了安全水平 一些研究人员为自己的定制特殊无人机和应用开发了自己的模拟环境 然而 使用多个无人机仿真环境很难建立可持续的研究 因为很
  • CSAPP第三版运行时打桩Segmentation fault

    CSAPP第三版7 13 3节提到了运行时打桩机制 它可以在运行时将程序中对共享库函数的调用进行截获 替换为执行自己的代码 这个机制基于动态链接器的LD PRELOAD环境变量 如果LD PRELOAD环境变量被设置为一个共享路径名的列表