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 ...
随机推荐
- c语言中malloc realloc 和calloc的联系与区别
(1)C语言跟内存分配方式 <1>从静态存储区域分配. 内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在.例如全局变量.static变量.<2> ...
- iOS- 三步快速集成社交化分享工具ShareSDK
http://www.cnblogs.com/qingche/p/3727559.html 1.前言 作为现在App里必不可少的用户分享需要,社交化分享显然是我们开发app里较为常用的. 最近因为公司 ...
- 关于PsCreateSystemThread函数
研究了1天这个...MSDN说的不是很清楚NTSTATUS PsCreateSystemThread( _Out_ PHANDLE ThreadHandle, _In_ UL ...
- HDU 1025 DP + 二分
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1025 求最长递增子序列,O(n^2)的复杂度超时,需要优化为O(n*logn) f[i]存储长度为i的最小 ...
- csu1306: Manor
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1306 解题思路:唬人的水题,只要按照他的意思打,就能过,不过,数组最好开大点.用到优先队列,也可以 ...
- ListView中加入Button后,Button的点击事件和ListView的点击事件冲突
1.在ItemView配置的xml文件里的根节点加入属性android:descendantFocusability="blocksDescendants" 2.在要加入事件的控件 ...
- BZOJ 4143: [AMPPZ2014]The Lawyer( sort )
水题... 排序搞出每天的会议有哪些, 然后再按照会议的开始时间和结束时间排序, 最晚开始的和最早结束的会议不是同一场而且最晚开始的时间>最早结束的会议就有可能方案 -------------- ...
- ant-学习记录二
<?xml version="1.0"?> <project name="targetStudy" default="mkdir&q ...
- servlet 将输入内容通过拼接页面的方式显示出来
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...
- 03-IOSCore - XML及解析、Plist
一.XML 可扩展标记语言 是什么?是一段有规范的字符串, 用在哪?用在任何地方 语法: * 结点Node <结点名 属性名="属性值"> 结点内容 </结点名& ...