Delphi 10.4 Update2中长波斯语字段调用TClientDataSet.Locate()触发访问冲突
问题原因分析与解决建议
问题重现
- 环境:Delphi 10.4 Update 2,采用
ADOQuery->DataSetProvider->TClientDataSet架构 - 场景:查询包含25字符全波斯语名称的字段,调用
Locate()方法时触发Access Violation - 测试SQL:
select 123 as 'تست تست تست تست تست' union all select 123 as 'تست تست تست تست تست' union all select 123 as 'تست تست تست تست تست'
- 现象:字段名缩短至16字符时,问题完全消失
核心原因
这是Delphi 10.4.2中TClientDataSet组件处理Unicode长字段名时的内存缓冲区越界问题:
- 波斯语字符属于UTF-16编码的Unicode字符,每个字符占用2字节。25个波斯语字符对应的字节数为50字节,而16个字符仅对应32字节。
TClientDataSet内部在存储、解析字段名,或执行Locate()时的字段匹配逻辑中,使用了固定大小的缓冲区。该缓冲区的设计未充分考虑Unicode字符的字节长度,当字段名字节数超过阈值时,会触发内存访问越界,进而导致Access Violation。- 数据从
ADOQuery经DataSetProvider传递到TClientDataSet的过程中,字段名的Unicode编码处理存在疏漏,长字段名未被正确适配内部缓冲区,最终引发内存错误。
临时解决办法
- 缩短字段名:直接将波斯语字段名控制在16字符以内(对应32字节),从根源避免触发缓冲区越界。
- 手动修改字段名:在
DataSetProvider的BeforeGetDataSet事件中,提前修改ADOQuery返回的字段名,缩短至安全长度后再传递给TClientDataSet,示例代码:
procedure TForm1.DataSetProvider1BeforeGetDataSet(Sender: TObject; DataSet: TDataSet); begin // 将长字段名替换为短名称 DataSet.FieldByName('تست تست تست تست تست').FieldName := 'TestShort'; end;
- 升级Delphi版本:该内存越界问题属于组件已知缺陷,后续Delphi版本(如11.x及以上)已修复此类Unicode字段名的处理逻辑,升级后可彻底解决问题。
内容的提问来源于stack exchange,提问作者Mohamad
相关产品推荐
相关产品推荐

