那谁的技术博客

感兴趣领域:高性能服务器编程,存储,算法,Linux内核
随笔 - 210, 文章 - 0, 评论 - 1183, 引用 - 0
数据加载中……

[经验教训总结]协议包头结构体定义不严谨造成的错误

今天遇到一个问题,调试了一天.

大致描述一下,移植一个开源项目的代码,原来在mips平台上运行正常,后来到arm平台的机器上运行,结果运行时出错了.

一般的,这样的问题,脑子里面第一下的反应就是由于字节序问题造成的.

我起初也是这么想的.因为从出错的现象来看,是某个字段不符合要求造成的出错.于是沿着这个思路去找BUG.抓包来分析,看上去也是这样的.但是,追踪的过程中发现,有多次收发报文的过程,这个字段,或者说拥有这个字段的结构体在多处都有使用,改了一处,在别的地方其它字段又有报错.

回头看代码,发现在最开始解析包头的时候,已经造成了紧跟着包头的某个字段出现异常,于是,想到是不是在不同的平台上,sizeof(某结构体)的数值不一样造成,要验证这一点,给包头结构体的定义加上严格按照一个字节对齐的限制,重新运行程序,可以了.

最后再来稍微详细一些看这个问题,假设包头结构体的定义是:
typedef unsigned short u16;

struct header
{
    u16 a;
    u16 b;
    u16 c;
};
如果解析的时候,sizeof(struct header) != sizeof(u16) * 3,那么使用sizeof(struct header)解析接收到缓冲区的数据就会出现问题,因为它会对紧跟着的数据也造成影响.程序的异常正是源于此.在代码的处理中,首先接收包头,对包头的数据进行了字节序转换,然后,又对紧挨着包头的结构体进行了相同的字节序转换,由于包头结构体的字节序转换同时影响了紧挨着的结构体中的数据,所以这些数据实际上被进行了两次的字节序转换,这才造成了这个问题"看上去"是字节序转换不当造成的"表面原因",如果跟着这个原因继续跟踪下去,以这个思路解决问题,治标而不治本.

总结:
1. 收发数据的结构体定义需要严谨一些,如果不能确定如何对齐,最好自己定义一个对齐的标准.
2. 经验有的时候也不见得就是好事,有时候会让自己陷入思维定式的怪圈,比如在这个问题的处理上,由于问题在切换了硬件平台的时候才出现,正好又是两个字节序不一样的硬件平台,所以经验将我的思路导向了字节序不正确这个方向上.



posted on 2009-10-15 20:32 那谁 阅读(5193) 评论(6)  编辑 收藏 引用 所属分类: 经验教训

评论

# re: [经验教训总结]协议包头结构体定义不严谨造成的错误  回复  更多评论   

有假设就写到代码里嘛。
随便找个编译单元:
static char assume[sizeof(header)==sizeof(u16)*3?1:-1];

或者就在header下方写:
typedef int assume[sizeof(header)==sizeof(u16)*3?1:-1]];

2009-10-15 23:35 | OwnWaterloo

# re: [经验教训总结]协议包头结构体定义不严谨造成的错误  回复  更多评论   

按照一字节对齐,不要使用编译器默认的。
2009-10-16 09:00 | guest

# re: [经验教训总结]协议包头结构体定义不严谨造成的错误[未登录]  回复  更多评论   

这种时候最好加上一个#pragma pack命令,对应于gcc好像是__attribute吧。
2009-10-16 17:31 | 欲三更

# re: [经验教训总结]协议包头结构体定义不严谨造成的错误  回复  更多评论   

学习分享!
2009-10-18 19:59 | 伊莎贝儿女装

# re: [经验教训总结]协议包头结构体定义不严谨造成的错误  回复  更多评论   

建议不要与语言,CPU相关。否则,你下次,还依然还要被教训
2009-10-18 21:35 | zdhsoft

# re: [经验教训总结]协议包头结构体定义不严谨造成的错误  回复  更多评论   

不太明白,你一个结构中三个成员都是相同类型的,什么情况下会出现整个结构的大小不等于成员类型大小的3倍?
2009-11-18 19:44 | MaTox

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理