dbtool一bug跟踪记
注:这篇日志是好多年前,我还在从兴公司时写的。现在都从从兴公司离职很久了,从兴也没落了,可惜。看了一下,虽然出现了部分代码,但不至于泄漏什么机密,查bug过程的原理也有可以让新手借鉴的地方,就原文照搬上来了。
dbtool是营帐研发部常用的一个类sqlplus数据库查询工具,它提供了较sqlplus更友好的输出界面,十分适合在命令行下操作,故在部门内部使用相当广泛。
不过它一直有一个bug,使用过程中偶尔会出现执行某条sql后core down的情况。但是由于这种情况较少见,而且bug出现随机性太大,所以一直也没人去管它。
今天早上加班过程中,居然又让我碰上这个bug了。不过这次bug很有规律,每次连接上数据库后立即执行“select userenv('language') from dual;”程序立即core down。
由于是周日,比较有空,而且天赐良机,居然能重现bug,于是决定花点时间解决这个bug。
首先使用dbx看一下程序在哪core
Segmentation fault(coredump)
bbkf:/home/report/c++/report/dbtool$dbx dbtool
Type 'help' for help.
[using memory image in core]
reading symbolic information ... Segmentation fault in malloc_y at 0x90000000005bb10 ($t1)
0x90000000005bb10 (malloc_y+0x5a4) stw r0,0x0(r5)
(dbx) where
malloc_y(0xa1, 0x0, 0x0, 0x7f7f7f7f, 0x2, 0x2d2d0049, 0x2d, 0x100233704) at 0x90000000005bb10
malloc_common_79_63(??) at 0x900000000058948
_Fancy_malloc__FUl(??) at 0x900000000451ae4
__nw__FUl(??) at 0x9000000004517c0
_Allocate__3stdHc_UlPc_Pc(??, ??) at 0x9000000004c5834
allocate__Q2_3std9allocatorXTc_FUlPCv(??, ??, ??) at 0x9000000004c57c4
_Copy__Q2_3std12basic_stringXTcTQ2_3std11char_traitsXTc_TQ2_3std9allocatorXTc__FUl(??, ??) at 0x9000000004c564c
_Grow__Q2_3std12basic_stringXTcTQ2_3std11char_traitsXTc_TQ2_3std9allocatorXTc__FUlb(??, ??, ??) at 0x9000000004c4ec8
assign__Q2_3std12basic_stringXTcTQ2_3std11char_traitsXTc_TQ2_3std9allocatorXTc__FPCcUl(??, ??, ??) at 0x9000000004c4bac
assign__Q2_3std12basic_stringXTcTQ2_3std11char_traitsXTc_TQ2_3std9allocatorXTc__FPCc(??, ??) at 0x9000000004c4974
__ct__Q2_3std12basic_stringXTcTQ2_3std11char_traitsXTc_TQ2_3std9allocatorXTc__FPCc(??, ??) at 0x9000000004c4880
GetColNameDisplay(std::basic_string<char,std::char_traits<char>,std::allocator<char> >&,std::basic_string<char,std::char_traits<char>,std::allocator<char> >&)(this = 0x0fffffffffffaba8, colsName = &(...), prompt = &(...)), line in "cmdDeal.cpp"
GetDBData(int)(this = 0x0fffffffffffaba8, bAutoContinue = ), line in "cmdDeal.cpp"
CCmdDeal::Run()(this = 0x0fffffffffffaba8), line in "cmdDeal.cpp"
main(argc = , argv = 0x0ffffffffffff338), line in "dbtool.cpp"
(dbx)
从上面可以看到,出错位置在string里面,根据经验,这种bug好解决,一般是string操作错误,例如将一个没有\0结尾的字符数组赋值给string
用vi打开cmdDeal.cpp,定位到884行,发现如下代码
+875 int CCmdDeal::GetColNameDisplay(string &colsName, string &prompt)
+876 {
+877 char chSplit = ' ';
+878 int i, len = 0;
+879 int rows = 0;
+880 int maxNameLen = 0;
+881 int lineSize = 0;
+882 int displayMode = 0;
+883 string s;
+884 string str45 = "-------------------------------------------------------------------"
+885 "-------------------------------------------------------------------";
居然是正常的字符串初始化出错! 这就郁闷了,这行代码怎么看都是正常的,根据经验,这种正常的代码出错,一般是由于前面某个位置出现了越界操作导致的。这种错误相对难查很多。
浏览了一下附近的代码,都没发现什么异常的代码,于是只能加上一些调试代码看能不能找出问题。经过一番尝试后发现,在GetColNameDisplay里面初始化长度较大的字符串就会导致程序core down。并且这个规律在GetDBData(调用GetColNameDisplay的函数)里面也有效。
这就好办了,只要找出在哪段代码执行后会出现这种奇怪的现象,问题代码应该就在那。
于是在程序里面加了N多个下面的代码片段
 {
     string str45 = "-------------------------------------------------------------------"
                                        "-------------------------------------------------------------------";
 string str451 = "-------------------------------------------------------------------"
                                        "-------------------------------------------------------------------";
     printf("[%s:%d]\n", __FILE__, __LINE__);
 }
上面的调试代码特意括在大括号里面的,目的有两个,
1 括号使得str45变成局部变量,这样不会出现变量冲突
2 保证str45尽快析构,以免影响错误定位
加上代码后编译运行,看程序在哪两行代码之间挂掉,接着在那两行代码中间增加更多调试代码,反复运行,很快就定位到了出错函数GetColumnInf。程序在调用这个函数之前调试代码执行不会有问题,在之后就挂了。GetColumnInf这个函数比较短,仔细看了一下,发现下面这段代码可能有问题。
vector<ColInf>::iterator it = m_vecColInf.begin();
int Index = ;
COciCursor cur( *m_pOracle );
COciColumnDesc coldesc; cur.Parse(strSql.c_str()); do
{
cur.DescribeColumn( Index, coldesc );
if (it->type != && it->type != )
{
it->prec = it->type== ? it->prec : coldesc.m_Prec;
}
it++;
Index++;
} while ( !cur.EndOfDesc() );
cur.Close();
代码里面对it操作时,没有判断it是否越界,整个函数看起来就这个最可能出现问题了。试着给while循环加了一个判断条件变成“while ( !cur.EndOfDesc() && it != m_vecColInf.end() );”
重新编译运行。
 jmzw@boss15test >select userenv('language') from dual; 
 USERENV('LANGUA
 -------------------------
 AMERICAN_AMERICA.ZHS16GBK
  rows selected.
猜对了,程序能正确输出,不会再core掉! 接下只需要分析这段代码为何会越界,修复即可。不过一看时间已经十一点多,不知不觉浪费了近半个上午,而且这段代码看起来作用只是获取数据库字段精度,不是很重要,所以此次根跟踪到此为止吧。
此次收获经验:写代码还是谨慎点,加多一些边界判断比较好,不然贪图一时方便可能导致花大把时间在定位bug
dbtool一bug跟踪记的更多相关文章
- Bug跟踪方法
		Bug跟踪函数调用方法 StackTraceElement mSte = new Exception().getStackTrace()[1]; Log.e("mmm", mSt ... 
- Bug跟踪的流程
		本文以翼发云协同项目管理系统为例子来讲解Bug跟踪的流程,它以工作流为中心的集成式Bug跟踪软件,它广泛地应用于研发行业的产品缺陷管理 与跟踪.事务跟踪.问题跟踪.任务跟踪.查询跟踪.需求管理.变更跟 ... 
- Android分组子级的不同视图布局之BUG奇遇记
		Android分组子级的不同视图布局之BUG奇遇记 最近在使用按日期分类列表,二级条目可能不一样,于是就想到了ExpandableListView. ExpandableListView的布局显示分割 ... 
- 提高效率!15款最好的 Bug 跟踪应用程序
		当涉及到开发项目时,其中比较重要的事情是它需要某种形式的错误和问题跟踪工具来发现和解决问题,否则会浪费大量的时间. 此外,你总是要标签应用来标示那些悬而未决的问题,而这种分期执行的项目进度将帮助您 ... 
- Visual Studio App Center 中的 Bug 跟踪服务
		我在之前的一篇文章 <使用 Visual Studio App Center 持续监视应用使用情况和问题> 中介绍了 App Center 的基本功能及使用入门,其中 诊断 可以自动手机用 ... 
- [异常特工]android常见bug跟踪
		前言 对app的线上bug的收集(友盟.云捕等)有时会得到这样的异常堆栈信息:没有一行代码是有关自身程序代码的.这使得对bug的解决无从下手,根据经验,内存不足OOM,Dialog关闭,ListVie ... 
- 线上应用bug跟踪查找-友盟统计
		线上的应用只要用心点点都能发现些bug,连微信,QQ也不列外.但是bug中最严重的算是闪退了,这导致了用户直接不能使用我们的app. 我们公司是特别注重用户反馈和体验的,我们会定期打电话咨询用户的使用 ... 
- bug生命周期&bug跟踪处理
		一.BUG BUG:软件的缺陷 1.BUG的定义:----与软件测试的目的对应 软件的BUG,狭义概念是指软件程序的漏洞或缺陷,广义概念除此之外还包括测试工程师或用户所发现和提出的软件可改进的细节.或 ... 
- 测试人必备:国内外最好用的6款Bug跟踪管理系统
		在移动互联网产品中,Bug会导致软件产品在某种程度上不能满足用户的需要.确保一个项目进展顺利,关键在于妥善处理软件中的BUG,那么,如何高效的管理BUG,解决BUG?在这里,我为大家搜集了几款优秀的B ... 
随机推荐
- robotframwork的WEB功能测试(一)—切换window窗口
			selenium2library提供的切换到新窗口的关键字,只有select window,而且也只能根据title.name.url去定位.如下图所示,明显在实际使用中是不够的. 所以这里总结了一下 ... 
- PHP扩展功能----发送邮件
			1.下载PHPMailer源码 github下载 (测试使用的是5.2.2 版本) 2.注册并登录网易邮箱(其他邮箱均可)[用于配置用户名和三方登录授权码,以及发送人邮箱地址] (1)开启POP3协 ... 
- Maven创建项目一些常见的问题
			1 .创建的项目中没有src/main/java.没有src/test/java 主要原因在于在创建项目的时候,使用的是系统自带的jdk,修改方法: 右键项目——Properties——javaBui ... 
- ActionBar自己定义改动无效解决方法
			假设程序支持API11下面的版本号,那么须要改动多个地方 values-v14 和values-v11以下的styles中也要写上 <style name="AppTheme" ... 
- 使用XWAF框架(4)——LunarCalendar日历组件
			XWAF提供了管理日历的com.xwaf.date.LunarCalendar静态类,可以直接使用,非常方便.该类包括六个主要静态方法: 4.1 isLeapYear(int year) 判断公历年 ... 
- Oracle分析函数(一)
			(一)分析函数语法 function_name(<argument>,<argument>...) over(<partition by clause><or ... 
- 线程队列-queue
			使用队列的目的: 解耦,使程序之间实现松耦合:提高处理效率 FIFO = 先进先出,first in first out LIFO = 后入先出,last in first out 生产者消费 ... 
- debian系统,启动Wireshark,出现Couldn't run /usr/bin/dumpcap in child process:权限不够
			这是由于当前用户没有权限运行/usr/bin/dumpcap造成的./usr/bin/dumpcap是Wireshark的包捕获引擎. 先用ls命令看一下dumpcap的权限情况:xy@debian- ... 
- 偏前端-HTML5 sessionStorage-会话存储
			sessionStorage 是HTML5新增的一个会话存储对象,用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据.本篇主要介绍 sessionStorage(会话存储) ... 
- 用JS遍历循环时覆盖了之前的值
			使用js遍历Echarts时,三个数据项,七个分类,遍历如下, 其他都没有问题,就是series.data里的数据只加载了一组,控制台显示数组的长度是7,可是下面的数据只有一个 发现把给数据项赋值的语 ... 
