Delphi CopyMemory在Win8上导致访问冲突

Delphi CopyMemory在Win8上导致访问冲突,delphi,64-bit,Delphi,64 Bit,我有一段代码,它使用Delphi XE3编译成64位COM DLL function TRPMFileReadStream.Read(var Buffer; const Count: Longint): Longint; begin if ((Self.FPosition >= 0) and (Count > 0)) then begin Result := Self.FSize - Self.FPosition; if ((Result > 0) an

我有一段代码,它使用Delphi XE3编译成64位COM DLL

function TRPMFileReadStream.Read(var Buffer; const Count: Longint): Longint;
begin
  if ((Self.FPosition >= 0) and (Count > 0)) then
  begin
    Result := Self.FSize - Self.FPosition;
    if ((Result > 0) and (Result >= Count)) then
    begin
      if (Result > Count) then
      begin
        Result := Count;
      end;
      CopyMemory(
        Pointer(@Buffer),
        Pointer(LongWord(Self.FMemory) + Self.FPosition),
        Result
      );
      Inc(Self.FPosition, Result);
      Exit;
    end;
  end;
  Result := 0;
end;
在Win7-64位上,上述操作可以正常工作。 但在Win8-64位上,相同的DLL文件将在CopyMemory上引发访问冲突。 CopyMemory在WinAPI.windows单元中实现

是这样的

procedure CopyMemory(Destination: Pointer; Source: Pointer; Length: NativeUInt);
begin
  Move(Source^, Destination^, Length);
end;
有什么想法吗?谢谢。

此时:

Pointer(LongWord(Self.FMemory) + Self.FPosition)
将64位指针截断为32位。因此存在访问冲突。相反,你需要

Pointer(NativeUInt(Self.FMemory) + Self.FPosition)
您的代码在Win7上也一样被破坏,但不知何故,您运气不好,只使用地址<4GB的指针运行过此代码


您应该运行一些自上而下的内存分配测试,以清除任何其他此类错误。

David指出了问题的根源-您的指针类型转换对于64位是错误的。更好的解决方案是使用指针算术,并让编译器为您处理指针大小:

CopyMemory(
  @Buffer,
  PByte(Self.FMemory) + Self.FPosition,
  Result
);
或:


为什么使用CopyMemory而不是标准的PAscal
Move
过程?或者,如果你不知道的话I don’我不喜欢标准函数,一个从?@Arioch'优化的函数。32位编译器使用FastCode
Move
,没有64位FastCode
Move
。我不能代表Doctorlai,@Arioch,但我更喜欢
CopyMemory
,因为我发现指针比未键入的引用参数更容易查找,我每天都用多种语言工作,所以有一个通用的API是很有帮助的。此外,由于API将所有内容直接转发给内置函数,因此任何人选择哪一个都没有什么区别。由于
CopyMemory
是内联的,因此编译器会发出相同的代码。所以,这取决于个人选择。我更喜欢使用语言惯例。在C++中,引用不流行,我会使用指针,但是在PASCAL中,我会使用引用,以与大多数代码一致。谢谢。帮了大忙。对我刚刚意识到这个愚蠢的错误。我将为所有内存指针快速替换所有LongWord(x)到NativeUInt()。我相信您会发现更多错误。运行自上而下分配测试的具体程度如何?请看这里:@DoctorLai我拒绝了您建议的编辑。很抱歉我真的是说不走运。不幸的是,这个错误直到现在才显现出来。任何在野外的代码都有这个bug。如果bug在更早的时候出现,那么缺陷较小的代码可能会逃逸。也许你还没有发布这段代码,但你知道我的意思。谢谢。。所以这个PByte需要{$POINTERMATH ON}来实现这个技巧,对吗?。两者都产生相同的代码,对吗?
POINTERMATH
仅由RTL为
PByte
自动打开
,但对于任何其他要使用指针算法的指针类型,都需要手动打开
它。我认为历史上偶然的情况下,它也为
PAnsiChar
打开。
Move(
  (PByte(Self.FMemory) + Self.FPosition)^,
  Buffer,
  Result
);