Indy10.2.5的危险做法
为了排查一个Bug今天无意看了看Indy源码,结果吓了一跳。TIdIOHandler.ReadLongWord函数用于读取通讯数据并转换成LongWord类型返回,它做用了一种危险的做法可能会导致数据传输不正确。
函数源码如下:
function TIdIOHandler.ReadLongWord(AConvert: Boolean): LongWord;
var
LBytes: TIdBytes;
begin
ReadBytes(LBytes, SizeOf(LBytes), False);
Result := BytesToLongWord(LBytes);
if AConvert then begin
Result := GStack.NetworkToHost(Result);
end;
end;
问题就在于ReadBytes(LBytes, SizeOf(LBytes), False)这句,和ReadInt64、ReadByte等其他函数明显不同,读取内容的长度为SizeOf(LBytes)而非SizeOf(LongWord)。这个LBytes空间为何物?它的定义是TIdBytes = TBytes , ==> TBytes = array of Byte,也就是说其他Byte数据类型。
LongWord类型有几长?在Delphi中它和UInt32一样是Cardinal类型,占4个字节位,即SizeOf(LongWord)=4。
LBytes类型又有几长?因为它是数组类型,最终会变成指针引用,所以和指针变量一样占一个机器字长,在32位机上就是32bit即4个字节位了,但是在64机上就要变成8个字节位了(我没64位机,请看官自行验证一下)。
这样,这个ReadLongWord函数在32位机上Read到的的确是LongWord,到了64位机上就成成了ReadInt64了,在网络通讯这种位位计较的地方数据就全乱套了。
Indy是Delphi中被使用得最多的网络通讯组件,它不断升级却也bug不断,很难想像Indy公司内部是如何进行测试的。如果是我的程序员写出这样的代码,我肯定得找他谈谈心了。
----------------------------------------------------------------------------------
- ReadBytes()仅仅是从缓冲区读取一个指向数据的指针,在这里的用法完全是正确的,适用于平台字位变化的情况。
真正有问题的,应该是
Result := BytesToLongWord(LBytes);
在转换的时候出错。
我所谓的“存在的问题是‘可能’”的,是指:
如果缓冲区中的数据属于int32范围,那么转换不会出问题;
如果缓冲区中的数据属于int64范围,那么由于转换的截断处理,的确会导致结果的错误。
- Re: nhconch 2009-12-14 23:36发表 [回复]

- 你的观点我同意一半,缓冲区中是何种数据类型是发送端决定的,接收端和发送端之间应有数据同步的协议才能有效通讯,如果发送端发出INT32的数据,接收端当INT64来处理当然会出错,但这是程序开发者的错误,不能怪Indy。
但Indy10.2.5的危险做法是在该用SizeOf(LongWord)的地方用了SizeOf(LBytes),这就是你说的“存在的问题是‘可能’”,因为没法保证不SizeOf(LongWord)永远等于SizeOf(LBytes)。
- 4楼 现货黄金 2009-11-23 13:18发表 [回复]

- 本人并不完全赞同作者的观点!
存在问题是“可能”的。
在Delphi中,出来High, Low, Succ, Pred, Inc, Dec, IntToStr, and IntToHex 以及其他一些明确含有"64"字样的函数支持64位操作之外,其他的函数几乎都会截断64位的变量成32位来操作。
其二就是和编译器有关,帮助中说的明白,除了int、指针类型会随着操作系统环境的字长而自动确定位数外,其他类型除非特殊指定,否则编译器是按照定长编译的。究竟是否存在32位环境下编译的程序到64上就会产生混乱,这需要实际测试!
再说,直接将32位环境下编译的程序用到64位环境下,还是值得商榷的!
- Re: nhconch 2009-11-23 18:11发表 [回复]

- 即使最新Delphi2010还是不支持64位的,虽然“直接将32位环境下编译的程序用到64位环境下还值得商榷”,但如果是用Delphi来做的,只能直接拿来用了。
含有"64"字样的函数操作的是64位变量(或直接数),不论32位还是64位环境得到的结果是一致的。
array of byte是数组,最终也是指针,就是你说的“随着操作系统环境的字长而自动确定位数”的,Indy10.2.5的这人危险做法就是在该取LongWord长度(固定值)的地方使用的指针的长度(会变的)。
- 3楼 jeanler 2009-11-22 19:47发表 [回复] [引用] [举报]

- 我在win7x86上试了一下, SizeOf(LBytes)=4, 我猜测这个应该跟windows版本或者编译器有关, 估计在64位编译器下可能就是8了
- Re: nhconch 2009-12-14 23:20发表 [回复] [引用] [举报]

- Delphi在编译时直接将SizeOf换成相应数据值,也就是说代码中写SizeOf(LBytes),生成EXE时直接被换成4了。
http://blog.csdn.net/nhconch/article/details/4840070
Indy10.2.5的危险做法的更多相关文章
- C#使用EmguCV实现视频读取和播放,及多个视频一起播放的问题
大家知道WPF中多线程访问UI控件时会提示UI线程的数据不能直接被其他线程访问或者修改,该怎样来做呢? 分下面两种情况 1.WinForm程序 1)第一种方法,使用委托: private delega ...
- Mybatis_总结_05_用_Java API
一.前言 使用 MyBatis 的主要 Java 接口就是 SqlSession.你可以通过这个接口来执行命令,获取映射器和管理事务. 二.主要类 (1)SqlSession 是由 SqlSessio ...
- Android之父Andy Rubin:被乔布斯羡慕嫉妒的天才
今年中国掀起一股“苹果热”,智能手机iPhone.平板电脑iPad遭疯抢,一度卖断货.然而,令许多人意想不到的是,在“苹果”的老家——美国市场,智能手机中卖得最火的并不是iPhone,而是Androi ...
- Java-MyBatis: MyBatis3 | Java API
ylbtech-Java-MyBatis: MyBatis3 | Java API 1.返回顶部 1. Java API 既然你已经知道如何配置 MyBatis 和创建映射文件,你就已经准备好来提升 ...
- 7.搭建hyperledger fabric环境及启动——2019年12月12日
2019年12月12日13:05:16 声明:从网络中学习整理实践而来. 1.介绍fabric Fabric 是一个面向企业应用的区块链框架,基于 Fabric 的开发可以粗略分为几个层面: 1. 参 ...
- 从源码角度分析 MyBatis 工作原理
一.MyBatis 完整示例 这里,我将以一个入门级的示例来演示 MyBatis 是如何工作的. 注:本文后面章节中的原理.源码部分也将基于这个示例来进行讲解.完整示例源码地址 1.1. 数据库准备 ...
- 让ASP.NET接受有“潜在危险”的提交
什么是有“潜在危险”的提交?马上动手写个简单的例子: 用Visual Studio创建一个空白的ASP.NET MVC程序,一切默认即可,添加一个空白的HomeController,增加一个Ind ...
- URL传递中文字符,特殊危险字符的解决方案(仅供参考)urldecode、base64_encode
很多时候,我们需要在url中传递中文字符或是其它的html等特殊字符,似乎总会有各种乱,不同的浏览器对他们的编码又不一样, 对于中文,一般的做法是: 把这些文本字符串传给url之前,先进行urlenc ...
- 从客户端中检测到有潜在危险的Request.Form值的详细解决方案
ASP.Net1.1后引入了对提交表单自动检查是否存在XSS(跨站脚本攻击)的能力.当用户试图用之类的输入影响页面返回结果的时候,ASP.Net的引擎会引发一个HttpRequestValidatio ...
随机推荐
- 网络编程TCP协议-聊天室
网络编程TCP协议-聊天室(客户端与服务端的交互); <span style="font-size:18px;">1.客户端发数据到服务端.</span> ...
- 使用jquery 1.7 及以后的版本 attr 问题
跟进jquery的代码进行检查,发现问题出在下面的代码中: if ( notxml ) { name = name.toLowerCase(); hooks = jQuery.attrHooks[ n ...
- AzureDev 社区活动获奖者公布
今天,我们高兴地宣布 AzureDev社区活动的获奖者,并向这 5 个非盈利技术教育组织发放 10 万美元奖金.在 2013 年的Build大会上宣布的 AzureDev 活动专注于通过代码改变世界, ...
- HDU2191:悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包)
Problem Description 急!灾区的食物依然短缺! 为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品 ...
- 简单字符串处理 hdu1062 Text Reverse
虽然这个题目一遍AC,但是心里还是忍不住骂了句shit! 花了一个小时,这个题目已经水到一定程度了,但是我却在反转这个操作上含糊不清,并且还是在采用了辅助数组的情况下,关系的理顺都如此之难. 其实我是 ...
- QPointer更安全,QScopedPointer自动出范围就删除,QSharedDataPointer帮助实现隐式共享
http://blog.csdn.net/hai200501019/article/details/8474582http://blog.csdn.net/hai200501019/article/d ...
- 面试题之——抽象类(abstract class)与接口(interface)的区别
抽象类可以有构造方法,接口中不能有构造方法.(虽然抽象类有构造方法,但它也不能被实例化) 抽象类中可以有普通成员变量,接口中没有普通成员变量. 抽象类和接口中都可以包含静态成员变量.抽象类中的静态成员 ...
- IOS引导页的编写
我们在第一次打开App的时候,通常不是直接进入App主界面,而是会有一个能左右滑动.介绍App功能的界面.我是用NSUserDefaults + UIScrollview实现. 新建一个类,继承UIV ...
- android Gallery滑动不流畅的解决
import android.content.Context; import android.util.AttributeSet; import android.view.KeyEvent; impo ...
- Action的返回值类型总结
Action的返回值 MVC 中的 ActionResult是其他所有Action返回类型的基类,下面是我总结的返回类型,以相应的帮助方法: 下面是这些方法使用的更详细的例子 一.返回View ...