简体   繁体   中英

Delphi 7 to Delphi XE5

i am porting a Server built on Indy TCP Component from Delphi 7 to XE5 for enabling 64-bit support. Now after i did all the porting and ran the server it worked just fine in testing environment. It worked great up till the user count exceeded 400. After that it starts creating Access violation errors. Sometimes breaking on the error points me into the indy source files and sometimes to the CPU window. I cant pinpoint the area of code in my sources where the error is generated.

While this kind of access violation error means i am accessing some object which is not yet instantiated, but why isnt the error generating when less users are online and the whole code is exactly same as the Delphi 7 code, the objects are accessed and freed in the same way as i was doing in Delphi 7.

I read somewhere that casting pointer related stuff should use NativeInt instead of Integer/Cardinal, Now in the code where i process incoming data, the code looks like this

procedure TMyContext.AddToPacketBuffer(Buffer: Pointer; Size: Integer);
var
  DestPtr: Pointer;
begin
  if PacketBufferPtr + Size<65536 then
  begin
    DestPtr := Pointer(Cardinal(FPacketBuffer)+Cardinal(PacketBufferPtr));
    Move(Buffer^,DestPtr^,Size);
    PacketBufferPtr := PacketBufferPtr + Size;
  end
  else
  begin
  end;
end;
  • FPacketBuffe r is a global Pointer declared in each TMyContext class, and PacketBufferPtr is an Integer variable declared in each TMyContext class

Should i use NativeInt here instead of Cardinal? could this be the root of the issue? if yes why is it not creating error when the user count is below 400, i tested using all the functions in local environment and no single portion of code generates an error.

Thanks

What you must understand about 64 bit code is that pointers are 64 bits wide. In contrast to 32 bit code where pointers are 32 bits wide. Now, the native integer types Integer and Cardinal are always 32 bits wide. Clearly you cannot fit all 64 bit values in a 32 bit type.

You are correct that this code is broken under 64 bit. Casting a 64 bit pointer to a 32 bit integer may lead to truncation. The code may work if the address fits in your 32 bit type. If you must perform such a cast then you need to cast to NativeInt or NativeUInt . And as well as changing the casts, you would need to declare any variables that hold pointers as NativeInt or NativeUInt .

Of course, ideally you should strive to avoid such casts altogether. You can do that by not using an Integer variable at to store pointers. Store pointers as pointers, avoid casting to integers and never suffer pointer truncation bugs.

That said, the name of PacketBufferPtr is very misleading. It is not a pointer as the name would suggest. It is an offset. It should be named PacketBufferOffset . It seems plausible that it will never exceed high(Integer) and so perhaps Integer is a sound choice. But it would never hurt to declare it to be NativeUInt .

So, assuming that you declare the pointers as PByte , and the offset as NativeUInt then the code would be written like this:

var
  FPacketBuffer: PByte;
  PacketBufferOffset: NativeUInt;
....    
procedure TMyContext.AddToPacketBuffer(Buffer: Pointer; Size: Integer);
var
  DestPtr: PByte;
begin
  if PacketBufferOffset + Size<65536 then
  begin
    DestPtr := FPacketBuffer + PacketBufferOffset;
    Move(Buffer^, DestPtr^, Size);
    inc(PacketBufferOffset, Size);
  end
  else
  begin
  end;
end;

And now the code is free of casts.

I recommend that you enable top down memory allocation as a debugging aid. This will flush out more bugs of this nature.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM