You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

64位下PChar指针运算触发范围检查错误的修复方案咨询

修复Delphi 64位下Str - fToIdent的运行时错误

问题根源分析

  • 非法指针运算:fToIdent处于初始nil状态,而Str是指向字符串末尾的有效PChar,对nil指针和有效指针做减法属于未定义行为。32位环境下可能因地址空间布局或编译器优化未触发崩溃,但64位环境下这种非法操作会直接触发运行时错误。
  • 类型不匹配:64位下PChar是8字节指针,Str - fToIdent的结果为NativeInt(64位整数),而fStringLen是32位Integer类型,赋值时会截断数据,进一步加剧错误风险。

最佳修复方案

方案1:确保fToIdent调用前完成初始化

fToIdent的设计意图应该是指向传入HashKey的字符串起始地址,需在调用HashKey前完成赋值:

// 调用HashKey前的示例代码
fToIdent := OriginalStr; // OriginalStr为传入HashKey的原始PChar参数
HashKey(OriginalStr);

方案2:内部记录起始指针,消除外部依赖

若fToIdent仅用于计算处理的字符串长度,可在函数内部新增局部变量记录起始地址,避免依赖外部未初始化状态:

function TdaSynHighlighterSQL.HashKey(Str: PChar): Integer;
var
  StartStr: PChar;
  function GetOrd: Integer;
  begin
    case Str^ of
      '_': Result := 1;
      'a'..'z': Result := 2 + Ord(Str^) - Ord('a');
      'A'..'Z': Result := 2 + Ord(Str^) - Ord('A');
      '@':
        if fDialect in [sqlMSSQL7, sqlMSSQL2K] then
          Result := 24
        else
          Result := 0;
      else Result := 0;
    end;
  end;

begin
  Result := 0;
  StartStr := Str; // 保存字符串起始指针
  while IsIdentChar(Str^) do
  begin
    Result := (2 * Result + GetOrd) and $FFFFFF;
    inc(Str);
  end;
  Result := Result and $FF;
  fStringLen := Str - StartStr; // 用局部指针计算长度,不再依赖fToIdent
end;

方案3:添加nil检查的防御性代码

若必须保留fToIdent的外部依赖,可先检查其有效性,避免非法运算:

// 在赋值语句前添加检查
if Assigned(fToIdent) then
  fStringLen := Str - fToIdent
else
  fStringLen := 0; // 或根据业务逻辑设置合理默认值

64位环境适配问题解析

  • 32位Delphi中,指针与Integer均为4字节,nil的地址为0,此时Str - nil会得到Str的内存地址数值(本质仍是非法操作,但32位运行时未严格拦截)。
  • 64位Delphi中,指针为8字节,NativeInt是64位整数,而Integer仍为32位。nil参与指针运算属于明确的未定义行为,且64位运行时对指针操作的合法性检查更严格,直接触发错误;同时64位结果赋值给32位变量会导致数据截断,进一步引发异常。

内容的提问来源于stack exchange,提问作者Jan Doggen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 04:58:09