🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.internet.socket
Article #341

Error handling in Indy 10

#341
From: Dennis Cote
Date: Wed, 16 Apr 2008 17:10
123 lines
6367 bytes
Hi All,

I have an application that has recently been converted to use Indy 10. 
This application runs correctly on Win XP. I am now testing the 
application under Vista. It does not work under Vista and I believe the 
issue has to do with Administrator rights, but that is not the immediate 
concern.

My concern is with the nature of the error checking being done in the 
Indy code. A failure to open a socket is generating a RangeError exception.

Just before it fails my application ends up in NewSocketHandle while 
trying to open an TIdICMPClient. This function is copied below.

function TIdStackBSDBase.NewSocketHandle(const ASocketType:TIdSocketType;
   const AProtocol: TIdSocketProtocol;
   const AIPVersion: TIdIPVersion = ID_DEFAULT_IP_VERSION;
   const AOverlapped: Boolean = False): TIdStackSocketHandle;
begin
   Result := CheckForSocketError(WSSocket(IdIPFamily[AIPVersion], 
ASocketType, AProtocol, AOverlapped));
end;

I have stepped through the assembly code of this routine to track the 
problem. This routine is essentially the one line.

IdStackBSDBase.pas.389: Result := 
CheckForSocketError(WSSocket(IdIPFamily[AIPVersion], ASocketType,
00837321 8B45FC           mov eax,[ebp-$04]
00837324 50               push eax
00837325 0FB64508         movzx eax,[ebp+$08]
00837329 50               push eax
0083732A 8BCE             mov ecx,esi
0083732C 85C9             test ecx,ecx
0083732E 7905             jns $00837335
00837330 E8F35FE9FF       call System::__linkproc__ BoundErr()
00837335 0FB6450C         movzx eax,[ebp+$0c]
00837339 8B1485246E9900   mov edx,[eax*4+$996e24]
00837340 8BC3             mov eax,ebx
00837342 8B30             mov esi,[eax]
00837344 FF96C4000000     call dword ptr [esi+$000000c4]
0083734A 8BD0             mov edx,eax
0083734C 85D2             test edx,edx
0083734E 7905             jns $00837355
00837350 E8D35FE9FF       call System::__linkproc__ BoundErr()
00837355 8BC3             mov eax,ebx
00837357 E81C0D0000       call Idstack::TIdStack::CheckForSocketError(int)
0083735C 85C0             test eax,eax
0083735E 7905             jns $00837365
00837360 E8C35FE9FF       call System::__linkproc__ BoundErr()

This code pushes the arguments to WSSocket() and then makes the virtual 
function call at 00837344. This ends up at WSSocket in the Windows stack.

function TIdStackWindows.WSSocket(AFamily, AStruct, AProtocol: Integer;
  const AOverlapped: Boolean = False): TIdStackSocketHandle;
begin
   if AOverlapped then begin
     Result := WSASocket(AFamily, AStruct, 
AProtocol,nil,0,WSA_FLAG_OVERLAPPED);
   end else begin
     Result := IdWinsock2.Socket(AFamily, AStruct, AProtocol);
   end;
end;

The argument AOverlapped is false, so it makes the call to 
IdWinsock2.Socket().

IdStackWindows.pas.600: Result := IdWinsock2.Socket(AFamily, AStruct, 
AProtocol);
00835494 50               push eax
00835495 51               push ecx
00835496 52               push edx
00835497 A12CF19900       mov eax,[$0099f12c]
0083549C 8B00             mov eax,[eax]
0083549E FFD0             call eax
IdStackWindows.pas.602: end;
008354A0 5D               pop ebp
008354A1 C20800           ret $0008

This function is failing (probably because of administrator rights) and 
returning a value of 0xFFFFFFFF (or -1) in the ax register to 
NewSocketHandle.

NewSocketHandle now does a range check on the result at 0083734A through 
0083734E. I'm not sure if that is correct but it seems like it might be 
(see below). In any case, the range check is failing because the result 
is negative (i.e the sign flag is set by the test instruction). This 
causes the code to call System::BoundErr() which generates the 
RangeError exception. The result of WSSocket() never makes it to the 
function CheckForSocketError() which is obviously intended to check this 
result because of this range check.

Now I'm no Delphi expert (i.e. it took me quite a while to confirm that 
LongWord and Longword are the same type because Delphi is case 
insensitive) but I tracked the types to see why this range check is 
being done. It seems reasonable to me, but I may be mistaken.

WSSocket() is defined to return a TIdStackSocketHandle result. This type 
is defined as a TSocket at line 115 of IdStatckConsts.pas. This type is 
in turn defined as PtrUint at line 219 of IdWinsock2.pas. Finally this 
type is defined as LongWord at line 674 of IdGlobal.pas.

The type of the argumnet to function CheckForSocketError() is defined as 
Integer at line 571 of IdStack.pas.

So NewSocketHandle() is trying to pass the LongWord result from 
WSSocket() to the Integer argument of CheckForSocketError(). Since 
LongWord is an unsiged type, its range is larger than the Integer 
arguments type. Hence the range check is required.

It seems to me that this range check will always fail if WSSocket 
returns 0xFFFFFFFF (or -1) for a failure, and hence we will never get to 
see the real reason for the failure that CheckForSocketError() is 
supposed to produce. I think some type casting must be needed to tell 
the compiler not to check the range of the result before passing it to 
CheckForSocketError(), but I'm not sure how that is done in Delphi. I 
also suspect this same error may exist in other places in the code.

Can anyone say if this analysis is correct, and if so how the result 
should be cast from unsigned to signed without the range check?

Dennis Cote
Technical Details
Message-ID: <480632fb$1@newsgroups.borland.com>
Path: arc1-ca.pugleaf.net!g2news1.google.com!news4.google.com!feeder.news-service.com!newsfeed.freenet.de!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail

Show Full Headers
Complete Article Headers
X-Google-Thread: 11508e,9330c485b2d28336,start
X-Google-Attributes: gid11508e,domainid0,public,usenet
X-Google-Language: ENGLISH,ASCII-7-bit
Date: Wed, 16 Apr 2008 11:10:20 -0600
From: Dennis Cote <denniscote@gmail.com>
User-Agent: Thunderbird 2.0.0.12 (Windows/20080213)
MIME-Version: 1.0
Newsgroups: borland.public.cppbuilder.internet.socket
Subject: Error handling in Indy 10
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
NNTP-Posting-Host: 142.179.167.5
Message-ID: <480632fb$1@newsgroups.borland.com>
X-Trace: newsgroups.borland.com 1208365819 142.179.167.5 (16 Apr 2008 10:10:19 -0700)
Lines: 130
Path: arc1-ca.pugleaf.net!g2news1.google.com!news4.google.com!feeder.news-service.com!newsfeed.freenet.de!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail