#1 2014-07-10 06:09:37

avista
Member
Registered: 2014-01-06
Posts: 63

AV in Interface Based Services

Using Project14ServerHttp:

type
  TCustomerData = packed record
    Id: Integer;
    AccountNum: RawUTF8;
    Name: RawUTF8;
    Address: RawUTF8;
  end;

  ICalculator = interface(IInvokable)
    ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}']
    function Add(n1,n2: integer): integer;
    function GetCustomer(CustomerId: Integer; out CustomerData: TCustomerData): Boolean;  <----------------
  end;

  [...]

type
  TServiceCalculator = class(TInterfacedObject, ICalculator)
  public
    function Add(n1,n2: integer): integer;
    function GetCustomer(CustomerId: Integer; out CustomerData: TCustomerData): Boolean; <----------------
  end;

function TServiceCalculator.Add(n1, n2: integer): integer;
begin
  result := n1+n2;
end;

function TServiceCalculator.GetCustomer(CustomerId: Integer; out CustomerData: TCustomerData): Boolean;
begin
  Result := True;
end;

Entering a string parameter instead of the expected integer value generates an AV:

http://localhost:888/root/Calculator.GetCustomer?CustomerId=John%20Doe

{
"ErrorCode":500,
"ErrorText":"Exception EAccessViolation: Access violation at address 004088A8 in module 'Project14ServerHttp.exe'. Read of address 00000004"
}

The error occurs here:

function TServiceMethod.InternalExecute(Instances: array of pointer;
  Par: PUTF8Char; Res: TTextWriter; out aHead: RawUTF8; out aStatus: cardinal;
  Options: TServiceMethodOptions; ResultAsJSONObject: boolean;
  BackgroundExecutionThread: TSynBackgroundThreadProcedure): boolean;

[...]

  finally // manual release memory for Records[], Objects[] and DynArrays[]
    for i := 0 to ArgsUsedCount[smvvObject]-1 do
      Objects[i].Free;
    for i := 0 to ArgsUsedCount[smvvDynArray]-1 do
      DynArrays[i].Wrapper.Clear;
    if Records<>nil then begin
      i := 0;
      for a := 0 to high(Args) do
        with Args[a] do
        case ValueType of
        smvRecord: begin
          RecordClear(pointer(Records[i])^,TypeInfo);  <----------------
          inc(i);
        end;
        {$ifndef NOVARIANTS}
        smvVariant: begin
          VarClear(PVariant(pointer(Records[i]))^); // fast
          inc(i);
        end;
        {$endif}
        end;
    end;
  end;

Offline

#2 2014-07-10 06:19:20

avista
Member
Registered: 2014-01-06
Posts: 63

Re: AV in Interface Based Services

On another note, decorating an interface method with an attribute causes an exception when registering the service:

type
  TMyAttribute = class(TCustomAttribute); <----------------

  ICalculator = interface(IInvokable)
    ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}']

    [TMyAttribute] <----------------
    function Add(n1,n2: integer): integer;
  end;

  [...]

// register our ICalculator service on the server side
aServer.ServiceRegister(TServiceCalculator,[TypeInfo(ICalculator)],sicShared);  <----------------
Exception class EInterfaceFactoryException with message 'ICalculator. method shall use register calling convention'. Process Project14ServerHttp.exe (9916)

I've implemented code that uses attributes to map URI templates to methods, but this error is preventing me from using it...

Thanks

Last edited by avista (2014-07-10 06:24:40)

Offline

#3 2014-07-10 08:41:19

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: AV in Interface Based Services

Are you sure you are using the latest "unstable" 1.18 version from our source code repository?
See http://synopse.info/fossil/wiki?name=Downloads#unstable

I was not able to reproduce the 2nd issue, so I did not even test the 1st one.

Offline

#4 2014-07-10 12:52:57

avista
Member
Registered: 2014-01-06
Posts: 63

Re: AV in Interface Based Services

Yes, I'm using the latest code from the repository.

I'm also using Delphi XE 2 Update 4 Hotfix 1 on Windows 7 6.1 (Build 7601: Service Pack 1)

However, my test case had an additional method, which I didn't show (like in the first case).  Without this method, it doesn't occur, but with this added method, it does:

type
  TMyAttribute = class(TCustomAttribute); <----------------

  ICalculator = interface(IInvokable)
    ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}']

    [TMyAttribute] <----------------
    function Add(n1,n2: integer): integer;

    function GetCustomer(CustomerId: Integer; out CustomerData: TCustomerData): Boolean;   <++++++++++++++
  end;

  [...]

// register our ICalculator service on the server side
aServer.ServiceRegister(TServiceCalculator,[TypeInfo(ICalculator)],sicShared);  <----------------

The error occurs here:

procedure TInterfaceFactory.AddMethodsFromTypeInfo(aInterface: PTypeInfo);
[...]

  for i := fMethodsCount to fMethodsCount+n-1 do begin
    // retrieve method name, and add to the methods list (with hashing)
    SetString(aURI,PAnsiChar(@PS^[1]),ord(PS^[0]));
    with PServiceMethod(fMethod.AddUniqueName(aURI,
      '%s.%s method: duplicated name',[fInterfaceTypeInfo^.Name,aURI]))^ do begin
      ExecutionMethodIndex := i+RESERVED_VTABLE_SLOTS;
      PS := @PS^[ord(PS^[0])+1];
      Kind := PME^.Kind;
      if PME^.CC<>ccRegister then
        raise EInterfaceFactoryException.CreateFmt(                <-----------------
          '%s.%s method shall use register calling convention',
          [fInterfaceTypeInfo^.Name,URI]);

[...]

And now, the exception message is truncated to only show a few characters (in the URI variable), so it looks like some kind of memory overwrite.

I can definitely reproduce both cases using the latest code.

Last edited by avista (2014-07-10 13:11:27)

Offline

#5 2014-07-10 14:01:08

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: AV in Interface Based Services

The attribute issue should be fixed by http://synopse.info/fossil/info/cef31cede1acd503

The record problem is really weird... Why on earth should you provide such incorrect input?
OK - code has been corrected to support such invalid content, and react without any GPF.
See http://synopse.info/fossil/info/08a6be5a267970336
I've added some regression tests according to those border cases.

Thanks a lot for the feedback and code to reproduce the issue.

Offline

#6 2014-07-10 15:59:02

avista
Member
Registered: 2014-01-06
Posts: 63

Re: AV in Interface Based Services

Why on earth should you provide such incorrect input?

LOL!

Well, since this will be a public facing API for developers, I can't be sure what kind of nonsense will be passed as parameters. wink

Thanks for fixing it!

Offline

Board footer

Powered by FluxBB