You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
horse.Provider.Socket.WebSocket.pas does not compile for Delphi on Linux since 3.3.3
#568
Every Horse release from 3.3.3 through 3.3.5 fails to compile under Delphi when the target platform is Linux (dcclinux64), because the Delphi/POSIX branch of THorseWebSocketSocketTransport.WaitReadable calls FD_SET(ASocket, LSet). In Delphi's POSIX RTL FD_SET is not a procedure: identifiers are case-insensitive, Posix.SysSelect declares the record typefd_set, and the RTL therefore names the macro _FD_SET. The compiler reads the call as a one-argument typecast and stops at the comma.
The unit is pulled in by Horse.Provider.Epoll, so any Delphi project using HORSE_PROVIDER_EPOLL on Linux is affected. 3.3.2 is the last release that builds. The fix is one character.
Environment
Horse
3.3.5 (tag 3.3.5, commit f3821dd); also 3.3.3 and 3.3.4
Compiler
Embarcadero Delphi for Linux 64 bit compiler version 37.0 (RAD Studio 37.0)
Target
Linux64
Defines
HORSE_PROVIDER_EPOLL (the unit fails on its own regardless of provider)
Host
Windows 11, cross-compiling
Steps to reproduce
Compiling the single unit is enough; no project or SDK is needed:
Delphi identifiers are case-insensitive, so FD_SET and fd_set are the same identifier, and fd_set is already the record type declared two lines above. FD_SET(ASocket, LSet) is therefore parsed as fd_set(ASocket, LSet), a typecast, which takes exactly one argument. Hence ')' expected but ',' found.
The RTL anticipates this. Posix.SysSelect.pas declares:
procedureFD_ZERO(var fdset: fd_set); inline;
procedure_FD_SET(fd: Integer; var fdset: fd_set); inline; // leading underscore: avoids the fd_set typeprocedureFD_CLR(fd: Integer; var fdset: fd_set); inline;
functionFD_ISSET(fd: Integer; const fdset: fd_set): Boolean; inline;
FD_ZERO, FD_CLR and FD_ISSET have no colliding type and are fine; only FD_SET needs the underscore.
Why it was not caught
The FPC branch uses fpFD_SET, so Lazarus on Linux is unaffected.
The Windows branch fills fd_array by hand (and its comment notes that Winapi.WinSock2 exposes FD_SET as a type, which is the same hazard in different clothing).
The compile matrix (tests/run_compile_matrix.ps1) and the Docker test images cover Delphi/Windows and FPC/Linux, but not Delphi/Linux, so the Delphi/POSIX branch was never compiled before release.
Introduced by commit cfacc5e ("fix: treat EAGAIN as no-data rather than disconnect in WebSocket socket transport", PR #549), first released in 3.3.3.
Fix
--- a/src/Horse.Provider.Socket.WebSocket.pas+++ b/src/Horse.Provider.Socket.WebSocket.pas@@ -296,7 +296,7 @@ function THorseWebSocketSocketTransport.WaitReadable(const ASocket: TSocket;
LTimeout: timeval;
begin
FD_ZERO(LSet);
- FD_SET(ASocket, LSet);+ _FD_SET(ASocket, LSet);
LTimeout.tv_sec := ATimeoutMS div 1000;
LTimeout.tv_usec := (ATimeoutMS mod 1000) * 1000;
Result := select(ASocket + 1, @LSet, nil, nil, @LTimeout) > 0;
Verified with that change applied to 3.3.5: the unit compiles for Linux64 (1413 lines, 0 errors) and for Win64, and a Delphi application using HORSE_PROVIDER_EPOLL links for Linux64 and runs.
It would also be worth adding a dcclinux64 compile of Horse.Provider.Socket.WebSocket.pas (and Horse.Provider.Epoll.pas) to the compile matrix so the Delphi/POSIX branches are exercised before a release. Compiling units for Linux needs only the compiler and lib\linux64\release; no Linux SDK is required unless something is linked.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Summary
Every Horse release from 3.3.3 through 3.3.5 fails to compile under Delphi when the target platform is Linux (
dcclinux64), because the Delphi/POSIX branch ofTHorseWebSocketSocketTransport.WaitReadablecallsFD_SET(ASocket, LSet). In Delphi's POSIX RTLFD_SETis not a procedure: identifiers are case-insensitive,Posix.SysSelectdeclares the record typefd_set, and the RTL therefore names the macro_FD_SET. The compiler reads the call as a one-argument typecast and stops at the comma.The unit is pulled in by
Horse.Provider.Epoll, so any Delphi project usingHORSE_PROVIDER_EPOLLon Linux is affected. 3.3.2 is the last release that builds. The fix is one character.Environment
3.3.5, commitf3821dd); also 3.3.3 and 3.3.4HORSE_PROVIDER_EPOLL(the unit fails on its own regardless of provider)Steps to reproduce
Compiling the single unit is enough; no project or SDK is needed:
Actual result
When compiled as part of an application the error surfaces as
Fatal: F2063 Could not compile used unit 'Horse.Provider.Socket.WebSocket.pas'.Expected result
The unit compiles. It does on Win64 (
dcc64, same source, 0 errors), and it did in 3.3.2 before this code existed.Cause
src/Horse.Provider.Socket.WebSocket.pas, Delphi/POSIX branch ofWaitReadable(lines 293-303 in 3.3.5):Delphi identifiers are case-insensitive, so
FD_SETandfd_setare the same identifier, andfd_setis already the record type declared two lines above.FD_SET(ASocket, LSet)is therefore parsed asfd_set(ASocket, LSet), a typecast, which takes exactly one argument. Hence')' expected but ',' found.The RTL anticipates this.
Posix.SysSelect.pasdeclares:FD_ZERO,FD_CLRandFD_ISSEThave no colliding type and are fine; onlyFD_SETneeds the underscore.Why it was not caught
fpFD_SET, so Lazarus on Linux is unaffected.fd_arrayby hand (and its comment notes thatWinapi.WinSock2exposesFD_SETas a type, which is the same hazard in different clothing).tests/run_compile_matrix.ps1) and the Docker test images cover Delphi/Windows and FPC/Linux, but not Delphi/Linux, so the Delphi/POSIX branch was never compiled before release.Introduced by commit
cfacc5e("fix: treat EAGAIN as no-data rather than disconnect in WebSocket socket transport", PR #549), first released in 3.3.3.Fix
Verified with that change applied to 3.3.5: the unit compiles for Linux64 (1413 lines, 0 errors) and for Win64, and a Delphi application using
HORSE_PROVIDER_EPOLLlinks for Linux64 and runs.It would also be worth adding a
dcclinux64compile ofHorse.Provider.Socket.WebSocket.pas(andHorse.Provider.Epoll.pas) to the compile matrix so the Delphi/POSIX branches are exercised before a release. Compiling units for Linux needs only the compiler andlib\linux64\release; no Linux SDK is required unless something is linked.All reactions