You are not logged in.
Pages: 1
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
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
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
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
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
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.
Thanks for fixing it!
Offline
Pages: 1