Invalid string length error

Delphi Tokyo, RO/DA version 9.4.109.1377

Hi guys,
I’m getting from time to time the following error on Delphi clients calling a method on Delphi Servers.

An exception was raised on the server: Stream read error: Invalid string length "2049".
: Exception EROUnregisteredServerException: An exception was raised on the server: Stream read error: Invalid string length "2049"

The function returns a TWideStringList which is declared as
TWideStringList = class(TROArray)

Which is basically an array of WideStrings as defined on the Service builder. It doesnt happen all the time, probably around 8 times a day out of a couple of thousand.

I see the call reaching the server and being executed and the values being returned but i think that on preparing the message back something goes wrong and crashes with the message above.

The length of the string may vary, so sometimes im getting
An exception was raised on the server: Stream read error: Invalid string length “1698914136”.
: Exception EROUnregisteredServerException: An exception was raised on the server: Stream read error: Invalid string length “1698914136”

But the number looks too big so it might be some buffer overrun of some sort.

Or

An exception was raised on the server: Unexpected end of stream.
: Exception EROUnregisteredServerException: An exception was raised on the server: Unexpected end of stream.

Just for the record and to see if it ticks someones imagination… this is the method.

function GetAllSessionsByRoutingList(const anEventSinkId: UnicodeString; const aRoutingList: GX_Common_Library_intf.TRoutingList): GX_Common_Library_intf.TWideStringList;

I’m using factory instantiation on RO, so I dont see a threading problem unless the guy doing the serialization back is not thread safe, or it is doing it from a “main” thread.

Any ideas, more than welcome. Thank you.

Hi,

TROMessage class and his descendants aren’t thread safe so if the same message is used simultaneously in two places on client-side, it may cause such problems.

Can you log broken message content for reviewing?

you can do it via overriding _Invoker class something like

type
  TMyMegaDemoService_Invoker = class(TMegaDemoService_Invoker)
  protected
    function CustomHandleMessage(const aFactory: IROClassFactory;
      const aMessage: IROMessage;
      const aTransport: IROTransport;
      out oResponseOptions: TROResponseOptions): boolean; override;
  end;

function TMyMegaDemoService_Invoker.CustomHandleMessage(
  const aFactory: IROClassFactory; const aMessage: IROMessage;
  const aTransport: IROTransport;
  out oResponseOptions: TROResponseOptions): boolean;
begin
  try
    result := inherited;
  except
    TMemoryStream((aMessage as IROBinMessage).Stream).SaveToFile('$$$.$$$');
  end;
end;

initialization
  fClassFactory := TROClassFactory.Create('MegaDemoService', Create_MegaDemoService, TMyMegaDemoService_Invoker);

For Code-First services, you can override TRORTTIInvoker.

Hi Evgeny,

Thank you for the response. That’s kind of a big issue. The only two parts of our setup that are marked as singletons are the Channel and the Message. Channel, we are using supertcp so its supposed to be thread safe and message, because it holds the Guid that identifies each client and we assumed some sort of cloning.

Do we make the message transient, create it every time and use the Channel Guid instead? We are heavily threaded so any tips on that direction are appreciated.

I will try to squeeze your code in on our production servers (otherwise i will probably not be able to reproduce it) but its going to be touchy. Yesterday we got the issue probably around 20 times (so it is higher than 8, my bad).

Thank you.

Hi,

lets to catch broken message and review it. it will give us some direction.