调试之剑:从堆里抢救丢失的博客文章

2024-03-22 03:59

本文主要是介绍调试之剑:从堆里抢救丢失的博客文章,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文/张银奎

很多使用计算机的人都曾经遇到过丢失数据的尴尬。记得我读大学时,很多文字编辑软件还没有自动存盘功能,而且寝室里偶尔会因为用电超过负荷而跳闸停电。每次断电时,如果赶上有人在电脑前写代码或者编辑文字,那么常常听到那位先生狠狠一跺脚(或者使劲一拍大腿),然后痛叫一声“唉呀,还有东西没存盘呢!”。因为输入的内容是临时保存在内存中的,如果忘记存盘或者在存盘前电脑死机或者突然断电,那么辛辛苦苦输入的东西就会化为乌有。

随着常用办公软件加入自动保存功能,因为忘记存盘而丢失数据的“悲剧”少了。但是偶尔也还会发生,因为自动存盘机制也有失灵的时候。最近一些年,基于网络的写作方式日益流行,比如写博客,在论坛上发帖子,或者点评别人的文章,对新闻发表看法等。这些写作很多是在浏览器里进行的,文字输入到不同形式的编辑框里,写作完毕时,发送到网站的服务器端保存。由于这种嵌入在网页中的编辑功能常常是没有自动存盘机制的,编辑内容一直临时保存在浏览器程序的内存空间中,如果编辑内容没有发送到服务器端,那么编辑的内容就可能丢失。笔者前不久就遇到了一次。

假日写作忙

故事发生在2010年的元旦假日,因为年底一个月很忙碌,所以久未写博客了,趁着元旦放假,略有空闲,于是想写点东西。一来练练手,免得本来就不熟练的文笔变得更加生疏;二来与网友们交流一下,免得朋友也生疏了。

于是上网,打开网页,准备写个短文。写什么呢?平时写的一般都是技术,不适合假日的气氛,于是想写点技术之外的闲话。放假前去了次闵行老街,就写这个吧,怀怀旧。写文章不是件简单的活,很多时候的确像赵本山说的那样,半天憋不出俩字。于是乎,就一篇简简单单的《重访闵行老街》(http://advdbg.com/blogs/advdbg_system/articles/3412.aspx),前前后后也用了几个小时。当然中间也有一些停顿,有时陪女儿玩一会,有时喝杯茶,这样到中午时,基本写好了,检查一遍就可以发出去了。但中饭时间到了,女儿强烈要求我煮意大利面给她吃,于是只好把写了大半的文章搁置下来。

厨房里忙活了一阵后,意大利面做好了。“老爸,意大利面煮的很棒”,女儿怪腔怪调的表扬给了我最好的奖励。吃过午饭,又想起写文章的事,看了一遍,改掉几个错别字,部分语句润色一下,自我感觉可以了,于是点击“发送”按钮,准备发布出去。

大意失博文

鼠标点下去后我就后悔了,或许被女儿刚才的表扬冲昏了头脑,我这个发送动作显然有些草率。应该在发送前先保存一下呀!虽然网页里没有保存功能,但是可以把内容Copy-Paste到记事本里保存到本地一份的。因为博客是在网页上写的,没有自动保存,如果发送失败,后果可能很严重。

导致发送失败的原因有很多,可能因为与服务器端的登录会话超时,可能因为服务器端网站服务存在故障,可能因为网络连接有问题。但是这时已经没有机会取消了,虽然还可以看到编辑的文字,可以选中,但是菜单中的Copy命令已经不管用了。

接下来看到的是浏览器与服务器艰难对话的过程,进度条缓慢的向前移动,状态条上提示“Connecting with server(正在连接服务器)”。这时我预感到事情不妙,这篇博客可能要白写,抱着无可奈何的心情又等了几秒钟后,问题真的出现了,浏览器切换到一个丑陋的错误提示页面,标题条上显示“Cannot find server(无法连接服务器)” (见图1),我一拍桌子,无语。

打开另一个浏览器,试图访问服务器,真的连不上,后来证明,服务器确实宕掉了,具体时间没有仔细查过,但肯定是在我写文章或者吃午饭的过程中,因为开始写这篇博客时还是连得上的。

根据经验,有时利用浏览器的回退功能还可以退回到刚才编辑的页面,救回所写的内容。于是点击Back按钮,但是浏览器并没有老老实实的回退到刚才的编辑页面,而是再次试图连接服务器,连接失败,又显示 “Cannot find server”,原因是前一个页面上的“自动脚本”会触发连接服务器的动作,糟糕的软件!

向前又向后来回了几次,仍无济于事,我意识到,刚才几个小时的工夫要白费了。这时老婆从书桌路过,听说我刚才写的东西丢了后,她哈哈大笑,“你也会犯这种错误的啊,我还以为只有我们这些人才犯这种错误哪,呵呵呵!”

是啊,这个错误是够低级的,要么应该用更好一点的工具来写,要么该先保存一下……但是现在说这个都没用了。

上调试器!

怎么办,重写一遍?不可接受。放弃拉倒?不可接受。想了一会后,我决定用调试器来寻找刚才写的文章。上调试器,对上调试器。因为文章应该还在内存里,在内存里,就应该可以用调试器找得到,找得到就可以读出来,读出来了就可以找办法恢复成可读的形式。

图1  向服务器端发送博客文章时失败[/caption]

启动WinDBG,点击File→ Attach to Process,然后选择浏览器进程(iexplore.exe)。因为系统中常常有多个浏览器程序的运行实例,因此首先要确认附加上的进程就是刚才写博客的那个进程,这可以通过尝试切换到刚才的浏览器窗口来判断,如果切换不过去,那就对了,证明这个进程已经被中断到调试中。

执行“lm”命令,可以看到进程中有几十个模块;执行“~”命令列一下线程,可以看到进程中有四十几个线程;用!heap命令列一下堆,有44个。要找的文章应该保存在当前进程的内存空间中,因此我们重点关心的是内存。在32位系统中,一个进程的内存空间有4GB大小,通常低2GB是用户态空间,给用户态代码使用,高2GB是内核空间,给系统代码使用。执行“!address”命令可以列出用户态空间中的所有区域:

技术4-2

在列出每个区域后,!address命令还会给出一个非常友好的统计报告,如图2所示。

图2  !address命令给出的内存统计报告[/caption]

根据经验,用于保存编辑文字的内存块应该是从堆上动态分配出来的。根据图2,当前进程里堆空间有116756KB大小,也就是100多MB,1亿多字节。也就是说,我们要在一亿多字节的堆中寻找几千个字节的博客文章。

搜索

看来我们要在1亿多字节的空间中寻找几千个字节的文章。如果用笨办法一个字节一个字节地找,那么真有点像大海捞针。茫茫1亿多字节的堆空间,在哪里找自己写的文章呢?

当然要依靠自动搜索,好在WinDBG已经为我们准备好了强大的内存搜索命令,可以在任意指定的空间范围内搜索不同类型的数据。

搜索吧!就从当前进程用户态空间的较低地址开始搜,找文章里的一句有特色的话:

0:045> s -u 10000 L80000 "当年在交大"

前几次尝试,什么都没找到,看来要扩大搜索范围:

0:045> s -u 10000 L8000000 "当年在交大"

延迟一刹那后,刷刷出来很多结果(见图3)。搜到了!这让人很高兴,说明数据还在内存里。

图3  搜索博客文章[/caption]

但是仔细看看搜索的结果后,又有点怀疑。因为WinDBG不支持中文显示,所以有点不确认上面搜到的信息。为了确认,执行“r”命令,观察ESP寄存器的值:

0:043> r esp

esp=02c9ffcc

然后使用内存编辑命令在栈上输入上面的中文字符(见图4),再用内存观察命令查看,证实上面搜索到的结果是对的,5f53就是“当”字的编码, 4ea4 5927 就是“交大”。

图4  编辑和观察栈[/caption]

图3中的搜索结果告诉我们搜到很多处,看来文章被复制了很多次,可能是不同阶段的处理函数分别作了拷贝。

使用哪一处的数据呢?当然希望是完整的,再搜索一下文章末尾的一个特征字:

s -u 10000 L8000000 "曙光"

也找到很多份(见图5),看来只要用对了工具和方法,刚刚苦苦寻找不可见的数据现在可以变得俯拾即是。

图5  搜索博客文章末尾的特征字符[/caption]

考虑到文章的长度在几千个字节大小,因此找图3和图5两个结果中差值大约为几KB的地址,观察一下属性:

0:045> !address 0728988a

06fa0000 : 07288000 - 00005000

Type     00020000 MEM_PRIVATE

Protect  00000004 PAGE_READWRITE

State    00001000 MEM_COMMIT

Usage    RegionUsageHeap

Handle   00150000

在堆上,靠谱!

保存到文件

接下来的目标是将数据从内存堆保存到文件,WinDBG已经帮我们准备好了一条命令:

0:045> .writemem c:\dumps\blog.txt 07288600  L2000

Writing 2000 bytes....

写好了,用记事本打开看一下(见图6):

图6  观察WinDBG保存出来的文章[/caption]

乱码,应该高兴还是失望?看到这种情况,老实说,我当时挺高兴的,根据经验这很像是中文,Unicode编码的,只不过没有按中文显示罢了。

怎么才能让编辑器程序按中文显示呢?方法很简单,对于文本文件,只要在文件开头加入Unicode文件的两个标识字符就行了,也就是0xFF FE。

怎么加入这两个字符呢?使用任何二进制编辑工具都可以,手头最方便的就是VC6。右键选择使用VC6打开,文件开头刚好有几个空闲的字符(<P>之类),将其修改为0xFF FE后,另存为blog_u.txt。再打开观看,便可以看到亲切的中文字符了(见图7)。

图7  加入Unicode标识后再观察[/caption]

哦,成功了!其实刚才加入0xFF FE那一步也可以在调试器里使用内存编辑命令来完成,编辑好再保存成文件。

回味

费了一番周折,丢失的文章终于又找到了。待服务器恢复正常后,整理一下,一篇失而复得的怀旧博文便发布出去了。回顾一下,首先多亏自己没有轻易放弃,一旦把浏览器程序关掉退出,那么内存空间就被销毁了,再想找到文章就更难了。另外,要感谢以调试器为核心的调试技术,正如我在很多地方都曾经说到的,调试技术绝对不仅仅是用来找BUG的,它的用途还有很多很多,在以后的文章中我们会不断给大家介绍。

主持人:张银奎

张银奎

《软件调试》一书作者,从事软件开发和研究10余年,对IA-32架构、操作系统内核、虚拟技术,尤其对软件调试有较深入的研究。翻译(合译)作品包括《数据挖掘原理》、《机器学习》、《人工智能:复杂问题求解的结构和策略》等。

(本文来自《程序员》杂志10年03期)

这篇关于调试之剑:从堆里抢救丢失的博客文章的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/834470

相关文章

ASIO网络调试助手之一:简介

多年前,写过几篇《Boost.Asio C++网络编程》的学习文章,一直没机会实践。最近项目中用到了Asio,于是抽空写了个网络调试助手。 开发环境: Win10 Qt5.12.6 + Asio(standalone) + spdlog 支持协议: UDP + TCP Client + TCP Server 独立的Asio(http://www.think-async.com)只包含了头文件,不依

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

vscode中文乱码问题,注释,终端,调试乱码一劳永逸版

忘记咋回事突然出现了乱码问题,很多方法都试了,注释乱码解决了,终端又乱码,调试窗口也乱码,最后经过本人不懈努力,终于全部解决了,现在分享给大家我的方法。 乱码的原因是各个地方用的编码格式不统一,所以把他们设成统一的utf8. 1.电脑的编码格式 开始-设置-时间和语言-语言和区域 管理语言设置-更改系统区域设置-勾选Bata版:使用utf8-确定-然后按指示重启 2.vscode

java计算机毕设课设—停车管理信息系统(附源码、文章、相关截图、部署视频)

这是什么系统? 资源获取方式在最下方 java计算机毕设课设—停车管理信息系统(附源码、文章、相关截图、部署视频) 停车管理信息系统是为了提升停车场的运营效率和管理水平而设计的综合性平台。系统涵盖用户信息管理、车位管理、收费管理、违规车辆处理等多个功能模块,旨在实现对停车场资源的高效配置和实时监控。此外,系统还提供了资讯管理和统计查询功能,帮助管理者及时发布信息并进行数据分析,为停车场的科学

起点中文网防止网页调试的代码展示

起点中文网对爬虫非常敏感。如图,想在页面启用调试后会显示“已在调试程序中暂停”。 选择停用断点并继续运行后会造成cpu占用率升高电脑卡顿。 经简单分析网站使用了js代码用于防止调试并在强制继续运行后造成电脑卡顿,代码如下: function A(A, B) {if (null != B && "undefined" != typeof Symbol && B[Symbol.hasInstan

php 7之PhpStorm + Nginx + Xdebug运行调试

操作环境: windows PHP 7.1.10 PhpStorm-2017.2.4 Xdebug 2.5.4 Xdebug helper 1.6.1 nginx-1.12.2 注意查看端口占用情况 netstat -ano //查看所以端口netstat -aon|findstr "80" //查看指定端口占用情况 比如80端口查询情况 TCP 0.0.0.0:8

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《考虑燃料电池和电解槽虚拟惯量支撑的电力系统优化调度方法》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源程序擅长文章解读,论文与完整源程序,等方面的知识,电网论文源程序关注python

【2025】基于Python的空气质量综合分析系统的设计与实现(源码+文档+调试+答疑)

博主介绍:     ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W+粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台的优质作者。通过长期分享和实战指导,我致力于帮助更多学生完成毕业项目和技术提升。 技术范围:     我熟悉的技术领域涵盖SpringBoot、Vue、SSM、HLMT