Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1482171
  • 博文数量: 226
  • 博客积分: 3997
  • 博客等级: 少校
  • 技术积分: 2369
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-19 17:26
个人简介

Never save something for a special occasion. Every day in your life is a special occasion.

文章分类

全部博文(226)

文章存档

2018年(5)

2017年(11)

2016年(1)

2015年(17)

2014年(14)

2013年(30)

2012年(5)

2011年(52)

2010年(107)

分类: C/C++

2018-04-25 21:14:14

通常,调试比编码的时间长。
好的编码习惯可以减少bug发生,从而节省时间。

即使是赶时间,也不能偷工减料。基本的编程规范还是要遵守的!

下面是一个教训:

我在调试一个简单的程序时,由于在第一个版本上加了一点点东西,
结果遇到一个奇怪的段错误:在 main 函数 return 0; 时发生段错误。

通常段错误发生时,查看堆栈可知具体的位置。而这次,提示似乎不明显

点击(此处)折叠或打开

  1. Program received signal SIGSEGV, Segmentation fault.
  2. 0xb6bcffdc in ?? () from /lib/arm-linux-gnueabihf/libc.so.6
  3. (gdb) bt
  4. #0 0xb6bcffdc in ?? () from /lib/arm-linux-gnueabihf/libc.so.6
  5. #1 0x0000a498 in main (
  6.     argc=<error reading variable: Cannot access memory at address 0x67344569>, argv=<error reading variable: Cannot access memory at address 0x67344565>)
  7.     at main.c:476
  8. Backtrace stopped: previous frame inner to this frame (corrupt stack?)
  9. (gdb)
奇怪,main 函数执行完,却出错了。
显然问题就出在 main 中,就是新添加的那一点点东西引来的。

加了什么东西呢? 上代码前,先交待下背景。

我写了一个访问某IM平台用户注册(RESTfull)的接口验证程序。
编码分2步:
编码实现 http 请求,调用用户注册接口。
添加注册回调函数,用于获取结果。

相关代码如下

点击(此处)折叠或打开

  1. // 在回调函数中解析并保存结果
  2. int imcb_regClient(cJSON *resp, void *puser)
  3. {
  4.     // ...
  5.     if (puser)
  6.     {
  7.         strcpy(puser, cJSON_GetStringItem(cli, "loginToken"));
  8.     }
  9.     return 0;
  10. }

  11. int main(int argc, char *argv[])
  12. {
  13.     // ...
  14.     // 设置用户注册回调函数
  15.     char loginToken[128] = {0};
  16.     imctx.rest_cb.pfun = imcb_regClient;
  17.     imctx.rest_cb.puser = loginToken;
  18.     // 执行注册操作
  19.     ret = regClient(&imctx, uid, friendlyName, mobile);
  20.     if (ret == 0)
  21.     {
  22.         // 打印结果
  23.         printf("regClient => loginToken=%s\n", loginToken);
  24.     }
  25.     // ...
  26.     return 0;
  27. }
第一步很顺利。第二步添加 rest_cb 后发生段错误。
同学,你能找出 bug 吗?

TIP:
很明显,段错误发生在 main 中,并且是由新添加的代码引起的!

前几天写一一篇“编译器的惩罚:warning-to-crash”,今天又遇到一个“没道理啊”错误。
每次遇到这种有意思的bug,我都会先想一想,然后叫jim同学来瞧一瞧看一看。
什么,他在忙,抽不开身 -- 好吧,他大概是看惯我们这些低级bug了。
好吧,我再想一想。
哈哈,灵光一闪,想到了。

常量 [128] ! 这家伙嫌疑最大。
看看打印出的 loginToken 值,177字节! 
锁定罪犯 -- 就是说你啊,C语言菜鸟!

别不接受菜鸟这个称呼,当你随意使用常量时你有想过数组会越界吗?
嗯,有想过,但这只是一个简单的测试程序,所以没在意。

狡辩!如果你是老鸟,会连这个常识都没有吗!

好吧,你赶时间。
我也赶时间,所以抓紧时间补漏:

点击(此处)折叠或打开

  1. #define MAX_USER_DATA 256

  2. char loginToken[MAX_USER_DATA] = {0};

  3. // 在回调函数中解析并保存结果
  4. int imcb_regClient(cJSON *resp, void *puser)
  5. {
  6.     // ...
  7.     if (puser)
  8.     {
  9.         //strcpy(puser, cJSON_GetStringItem(cli, "loginToken"));
  10.         strncpy(puser, MAX_USER_DATA, cJSON_GetStringItem(cli, "loginToken"));
  11.     }
  12.     return 0;
  13. }




阅读(2581) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~