Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Access violation when out record used instead of function result.


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 3 - Last Post: Aug 24, 2017 5:00 PM Last Post By: Remy Lebeau (Te...
Hafedh TRIMECHE

Posts: 107
Registered: 12/29/06
Access violation when out record used instead of function result.  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 24, 2017 1:41 PM
Delphi Delphi 10.2 Version 25.0.27659.1188

InitRecord is used to initialize record having dynamic fields.
procedure InitRecord(Out Buffer;const Size:Integer;const B:Byte=0);
begin
  FillChar(Buffer,Size,B);
end;


  TAcquirerReport=
  packed record
    Head               : TDBRecordHeader;
    Year               : Word;
    Month              : Word;
    Day                : Word;
    AcquirerBIC        : string;
    Account            : string;
    ProfileID          : Cardinal;
    IssuerID           : Cardinal;
    AccountCurrency    : Word;
    InstitutionAccount : string;
    Currency           : Word;
    MCC                : Word;
    MCCText            : string;
    ProfileDescription : string;
    AcceptedCount      : Int64;
    Accepted           : Extended;
    DeclinedCount      : Int64;
    Declined           : Extended;
 
    ConvertedAmount    : Extended;
 
    FeeUntaxed         : Extended;
    FeeVAT             : Extended;
    FeeTotal           : Extended;
 
    TxFlat             : Extended;
    TxTotal            : Extended;
    ExchangeFlat       : Extended;
    ExchangeTotal      : Extended;
    [Filler]
    IssuerBIC          : string;
    IssuerInstitution  : string;
  end;


This procedure generates an access violation
procedure TransactionToAcquirerReport(const AcquirerTx:TAcquirerTx;out Report:TAcquirerReport);
begin
  InitRecord(Report,SizeOf(Report));
  Report.Year  := YearOf(AcquirerTx.DateTime);
  Report.Month := MonthOf(AcquirerTx.DateTime);
  Report.Day   := DayOf(AcquirerTx.DateTime);
  with Report do
  begin
    Account            := AcquirerTx.Account;
    AcquirerBIC        := AcquirerTx.BIC;
    InstitutionAccount := AcquirerTx.InstitutionAccount;
    ProfileID          := AcquirerTx.TerminalProfile;
    AccountCurrency    := AcquirerTx.AccountCurrency;
    IssuerID           := AcquirerTx.IssuerID;
    Currency           := AcquirerTx.CurrencyCode;
    MCC                := AcquirerTx.MCC;
    if ISO8583GoodStatus(AcquirerTx.ResponseCode) then
    begin
      AcceptedCount   := 1;
      Accepted        := AcquirerTx.Amount;
      ConvertedAmount := AcquirerTx.ConvertedAmount;
      with AcquirerTx.TerminalData do
      begin
        if NationalTotal>0 then
        begin
          TxFlat  := National;
          TxTotal := NationalTotal;
        end
        else
        begin
          if OnUsTotal>0 then
          begin
            TxFlat  := OnUs;
            TxTotal := OnUsTotal;
          end
          else
          begin
            TxFlat  := International;
            TxTotal := InternationalTotal;
          end;
        end;
      end;
      ExchangeFlat          := AcquirerTx.TerminalData.Exchange;
      ExchangeTotal         := AcquirerTx.TerminalData.ExchangeTotal;
      FeeUntaxed            := AcquirerTx.FeeUntaxed;
      FeeVAT                := AcquirerTx.FeeVAT;
      FeeTotal              := AcquirerTx.FeeTotal;
    end
    else
    begin
      DeclinedCount := 1;
      Declined      := AcquirerTx.Amount;
    end;
  end;
end;


This function is executed as expected
function TransactionToAcquirerReport(const AcquirerTx:TAcquirerTx):TAcquirerReport;
begin
  InitRecord(Result,SizeOf(Result));
  Result.Year  := YearOf(AcquirerTx.DateTime);
  Result.Month := MonthOf(AcquirerTx.DateTime);
  Result.Day   := DayOf(AcquirerTx.DateTime);
  with Result do
  begin
    Account            := AcquirerTx.Account;
    AcquirerBIC        := AcquirerTx.BIC;
    InstitutionAccount := AcquirerTx.InstitutionAccount;
    ProfileID          := AcquirerTx.TerminalProfile;
    AccountCurrency    := AcquirerTx.AccountCurrency;
    IssuerID           := AcquirerTx.IssuerID;
    Currency           := AcquirerTx.CurrencyCode;
    MCC                := AcquirerTx.MCC;
    if ISO8583GoodStatus(AcquirerTx.ResponseCode) then
    begin
      AcceptedCount   := 1;
      Accepted        := AcquirerTx.Amount;
      ConvertedAmount := AcquirerTx.ConvertedAmount;
      with AcquirerTx.TerminalData do
      begin
        if NationalTotal>0 then
        begin
          TxFlat  := National;
          TxTotal := NationalTotal;
        end
        else
        begin
          if OnUsTotal>0 then
          begin
            TxFlat  := OnUs;
            TxTotal := OnUsTotal;
          end
          else
          begin
            TxFlat  := International;
            TxTotal := InternationalTotal;
          end;
        end;
      end;
      ExchangeFlat          := AcquirerTx.TerminalData.Exchange;
      ExchangeTotal         := AcquirerTx.TerminalData.ExchangeTotal;
      FeeUntaxed            := AcquirerTx.FeeUntaxed;
      FeeVAT                := AcquirerTx.FeeVAT;
      FeeTotal              := AcquirerTx.FeeTotal;
    end
    else
    begin
      DeclinedCount := 1;
      Declined      := AcquirerTx.Amount;
    end;
  end;
end;


What is causing this problem?
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Access violation when out record used instead of function result.  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 24, 2017 2:12 PM   in response to: Hafedh TRIMECHE in response to: Hafedh TRIMECHE
Hafedh TRIMECHE wrote:

InitRecord is used to initialize record having dynamic fields.

Why are you using 'out' for an untyped parameter? The whole purpose of
'out' is to let the compiler default-initialize a parameter based on
its type, but it can't do that if it doesn't know what the type is. It
is not an error to use 'out' for an untyped parameter, but it doesn't
gain you anything either, so you should use 'var' instead of 'out':

procedure InitRecord(var Buffer; const Size: Integer; const B: Byte =
0);


This procedure generates an access violation

But you didn't say WHERE the AccessViolation is occuring. Which line
of code?

--
Remy Lebeau (TeamB)
Hafedh TRIMECHE

Posts: 107
Registered: 12/29/06
Re: Access violation when out record used instead of function result.  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 24, 2017 3:25 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thank you Remy for this clarification.

I use out to avoid memory leak generated by record's initialization with FillChar when it contains dynamic fields.

The access violation is generated within a RTTI parser having AcquirerTx as an input parameter. The debugger states that the value of AcquirerTx is invisible after the procedure exit.

Replacing out by var gives the good result.
procedure TransactionToAcquirerReport(const AcquirerTx:TAcquirerTx;var Report:TAcquirerReport);


Remy Lebeau (TeamB) wrote:
Hafedh TRIMECHE wrote:

InitRecord is used to initialize record having dynamic fields.

Why are you using 'out' for an untyped parameter? The whole purpose of
'out' is to let the compiler default-initialize a parameter based on
its type, but it can't do that if it doesn't know what the type is. It
is not an error to use 'out' for an untyped parameter, but it doesn't
gain you anything either, so you should use 'var' instead of 'out':

procedure InitRecord(var Buffer; const Size: Integer; const B: Byte =
0);


This procedure generates an access violation

But you didn't say WHERE the AccessViolation is occuring. Which line
of code?

--
Remy Lebeau (TeamB)

Edited by: Hafedh TRIMECHE on Aug 24, 2017 3:35 PM
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Access violation when out record used instead of function result. [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Aug 24, 2017 5:00 PM   in response to: Hafedh TRIMECHE in response to: Hafedh TRIMECHE
Hafedh TRIMECHE wrote:

The access violation is generated within a RTTI parser having
AcquirerTx as an input parameter. The debugger states that the value
of AcquirerTx is invisible after the procedure exit.

Please reduce your code to a reproducable example, and then post that.
The code you showed earlier is not complete.

Replacing out by var gives the good result.

Only if you pass it an uninitialized record. Otherwise, your
FillChar() will cause a leak for an initialized record that contains
allocated data in it. 'out' would finalize the record to free any
allocated memory properly before you then zero out the record.

--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02