Simple benchmarking framework, or how to enumerate published methods in Delphi

1

The article describes an old trick of enumerating and invoking published methods of a class. The trick is used in DUnit testing framework, and I came to the same idea while trying to bring some order into my benchmark routines.

So the idea was to declare benchmark routines as published methods of a class

type
  TDemoRunner = class(TRunner)
  published
    procedure Proc1;
    procedure Proc2;
  end;

and get these published methods automatically invoked by the framework.

I don’t want to dig into details of the solution because it supposed to be the solution that “just works” without need to dig into internals.

{$M+}
unit Runners;

interface

uses
  SysUtils;

const
  MillisPerDay = 24 * 60 * 60 * 1000;

type
  TBenchProc = procedure of object;

  PMethInfo = ^TMethInfo;
  TMethInfo = record
    Code: Pointer;
    Name: string;
  end;

  TMethArray = array of TMethInfo;

type
  TRunnerClass = class of TRunner;

  TRunner = class
  protected
    FElapsedMs: Integer;
    FMethArray: TMethArray;
    FMethIndex: Integer;
    procedure LogProc; virtual;
    procedure Init; virtual;
    procedure Run; virtual;
  public
    constructor Create; virtual;
    class procedure Exec(AClass: TRunnerClass);
  end;

implementation

{ TRunner }

constructor TRunner.Create;
begin
end;

procedure TRunner.Init;
type
  PMethodTable = ^TMethodTable;
  TMethodTable = packed record
    Count: SmallInt;
    Data: record end;
  end;

  PMethEntry = ^TMethEntry;
  TMethEntry = packed record
    Len: Word;
    Code: Pointer;
    Name: ShortString;
  end;

var
  MethTable: PMethodTable;
  I: Integer;
  Entry: PMethEntry;

begin
  FMethArray:= nil;
  MethTable:= PPointer(PByte(Self.ClassType) + vmtMethodTable)^;
  if (MethTable = nil) or (MethTable.Count <= 0) then Exit;
  Entry:= @MethTable.Data;
  SetLength(FMethArray, MethTable.Count);
  for I:= 0 to MethTable.Count - 1 do begin
    FMethArray[I].Code:= Entry.Code;
    FMethArray[I].Name:= string(Entry.Name);
    Inc(PByte(Entry), Entry.Len);
  end;
end;

procedure TRunner.LogProc;
begin
  Writeln(FMethArray[FMethIndex].Name, ' .. time: ', FElapsedMs, ' ms');
end;

procedure TRunner.Run;
var
  Proc: TBenchProc;
  StartTime: TDateTime;
  I: Integer;

begin
  Init;
  for I:= 0 to Length(FMethArray) - 1 do begin
    TMethod(Proc).Code:= FMethArray[I].Code;
    TMethod(Proc).Data:= Self;
    StartTime:= Now;
    Proc();
    FElapsedMs:= Round((Now - StartTime) * MillisPerDay);
    FMethIndex:= I;
    LogProc;
  end;
end;

class procedure TRunner.Exec(AClass: TRunnerClass);
var
  Instance: TRunner;

begin
  Instance:= AClass.Create;
  try
    Instance.Run;
  finally
    Instance.Free;
  end;
end;

end.

Here is the usage example.

Demo benchmarking class:

unit DemoRunners;

interface

uses Runners;

type
  TDemoRunner = class(TRunner)
  published
    procedure Proc1;
    procedure Proc2;
  end;

implementation

{ TDemoRunner }

procedure TDemoRunner.Proc1;
begin
  Writeln('Running Proc1');
end;

procedure TDemoRunner.Proc2;
begin
  Writeln('Running Proc2');
end;

end.

and benchmarking console application:

program BenchDemo;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Runners in 'Runners.pas',
  DemoRunners in 'DemoRunners.pas';

begin
  try
    TRunner.Exec(TDemoRunner);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

The output:
_bench

On the record initialization/finalization in Delphi

10

If a Delphi record type contains managed fields Delphi uses special initialization and finalization routines for the record instances. Unfortunately these routines use some kind of RTTI information and slow; they could be made much faster.

I have written a simple benchmark to find out how the built-in record initialization/finalization routines can possibly slow down my BigInteger implementation:

program CustomBench;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TIRec = record
    II: IInterface;
  end;

  TPRec = record
    PP: Pointer;
  end;

procedure ITest(const AI: IInterface);
var
  IR: TIRec;

begin
  IR.II:= AI;
end;

procedure PTest(const AI: IInterface);
var
  PR: TPRec;

begin
  PR.PP:= nil;                  // custom initialization
  try
    IInterface(PR.PP):= AI;
  finally
    IInterface(PR.PP):= nil;      // custom finalization;
  end;
end;

procedure TestI(const AI: IInterface; Count: Integer);
begin
  while Count > 0 do begin
    ITest(AI);
    Dec(Count);
  end;
end;

procedure TestP(const AI: IInterface; Count: Integer);
begin
  while Count > 0 do begin
    PTest(AI);
    Dec(Count);
  end;
end;

procedure BenchMark(Count: Integer);
const
  MillisPerDay = 24 * 60 * 60 * 1000;

var
  II: IInterface;
  StartTime: TDateTime;
  ElapsedMillis1: Integer;
  ElapsedMillis2: Integer;

begin
  II:= TInterfacedObject.Create;
  StartTime:= Now;
  TestI(II, Count);
  ElapsedMillis1:= Round((Now - StartTime) * MillisPerDay);
  Writeln('Built-in initialization/finalization: ', ElapsedMillis1, ' ms.');
  StartTime:= Now;
  TestP(II, Count);
  ElapsedMillis2:= Round((Now - StartTime) * MillisPerDay);
  Writeln('Custom initialization/finalization: ', ElapsedMillis2, ' ms.');
  Writeln('Built-in slowdown: ',
    Round((ElapsedMillis1/ElapsedMillis2 - 1) * 100), '%');
  II:= nil;
end;

begin
  try
    BenchMark(10000000);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  ReadLn;
end.

The typical result I am getting on my laptop (Delphi XE, 32 bits) is:

Slow

Not a showstopper, the actual slowdown for a real code which is doing something will be significantly less, still the slowdown is not negligible.

Definitions of semantic security

0
  1. One-time semantic security.
  2. The simplest definition of semantic security is one-time semantic security which naturally applies to stream ciphers:

    An adversary sends two plaintext messages of equal length to the challenger and receives one encrypted message; semantic security means an adversary can’t distinguish which plaintext message was encrypted.

    The above is more an intuition than a definition; the strict formal definition involves details not suitable here.

    In practice a semantically secure stream cipher is as good as perfect one-time pad.

    The block cipher’s electronic codebook (ECB) mode of operation is not one-time semantically secure; the reason is ECB mode always maps identical plaintexts to identical ciphertexts. To win the game an adversary creates two messages of two blocks length; the first message consists of two identical blocks and the second consists of two different blocks; after receiving the ciphertext an adversary checks whether the ciphertext blocks are identical or not and decides which plaintext was encrypted. On the other hand the cipher block chaining (CBC) mode is one-time semantically secure.

  3. Semantic security under the chosen plaintext attack (CPA).
  4. One-time semantic security is not good for block ciphers because the block ciphers usually use many-time keys, so we need many-time security definition:

    An adversary sends q pairs of plaintext messages to the challenger; the challenger encrypts either the first messages or the second messages and sends them to an adversary; semantic security means an adversary can’t distinguish which messages (first or second) were encrypted.

    The above semantic security under CPA definition gives more power to an adversary. The CBC mode is semantically secure under CPA only if an initialization vector (IV) is unpredictable (random). If an adversary can predict the next IV used by the challenger he can create a one-block message which he can encrypt himself and use this message to win the CPA game.

    The semantic security under CPA implies that an adversary can force the challenger to encrypt the messages of his choice; all an adversary has to do is to send a pair of identical messages to the challenger and receive the ciphertext.

    So in the CPA game an adversary can get q-1 encrypted messages of his choice, then send the last q-th pair of different messages, receive the ciphertext and his goal now is to decide which message was encrypted.

  5. Semantic security under the chosen ciphertext attack (CCA).
  6. CCA game gives even more power to an adversary. Now an adversary can send queries of two types to the challenger – first type are the same pairs of plaintext messages as in the CPA game and the second type queries are ciphertexts which the challenger decrypts and sends the decrypted plaintexts back to an adversary. The adversary goal is to decide which plaintext messages, first or second, were encrypted in the queries of the first type.
    The only limitation is that an adversary can’t send ciphertexts which he receives from the challenger in the first type queries because otherwise the game is senseless.

    In the CCA game an adversary can force the challenger both to encrypt the plaintexts of his choice and decrypt ciphertexts of his choice; his goal again is to distinguish between the plaintext messages and decide which messages were encrypted.

    The CCA security is required against an active adversary, who can not only eavesdrop but also tamper, for example by blocking or injecting network packets. The CBC mode with random IV is not semantically secure under CCA. To be secure under CCA a system should provide CPA secure encryption with message authentication; the examples are SSL and IPSec protocols.

Numerics 0.55 released

0

Numerics 0.55 is available for download

The main improvements are:

1) Explicit DLL load is supported by the function

function LoadNumerics(const Name: string = ''): TF_RESULT;

and this is now the recommended method to load the dll because it enables error handling:

if LoadNumerics() < 0 then
  raise Exception.Create('!!! - DLL load error');

if the LoadNumerics was not called the dll is loaded transparently when needed.

2) More BigInteger functions implemented:

2.1) Integer square root:

    class function Sqrt(A: BigInteger): BigInteger; static;

2.2) Euclid algorithm (aka Greatest Common Divisor) and Extended Euclid algorithm:

    class function GCD(A, B: BigInteger): BigInteger; static;
    class function EGCD(A, B: BigInteger; var X, Y: BigInteger): BigInteger; static;

2.3) Modular arithmetic:

    class function ModPow(const BaseValue, ExpValue, Modulo: BigInteger): BigInteger; static;
    class function ModInverse(A, Modulo: BigInteger): BigInteger; static;

Most of the above functions were written while I was doing the programming assignments of the Coursera Cryptography 1 course by prof. Dan Boneh. It was fun to use my own BigInteger implementation.

3) C++ support added. I used free CodeBlocks IDE to port the PiBench console application to C++.

Merry Christmas and Happy New Year!

Goodbye, TObject

7

I’m not using TObject in my Delphi code anymore. Sure I use the core classes like TStream derived from TObject but I don’t derive my own classes from TObject or descendant classes. I am using a different OOP paradigm instead.
It all started when I was looking for a simple-to-use and efficient BigInteger type in Delphi and the solution seems absolutely evident now when I am looking back at it:

type
  IBigNumber = interface
/*
  interface methods
*/
  end;

type
  BigInteger = record
  private
    FNumber: IBigNumber;
  public
/*
  public methods and overloaded operators
*/
  end;

The BigInteger type is an interface reference wrapped in the advanced record; SizeOf(BigInteger) = SizeOf(Pointer).

Let us generalize the above idea. Instead of

type
  TMyObject = class
/*
..
*/
  end;

we use the alternative:

type
  IMyObject = interface
/*
..
*/
  end;

  TMyObject = record
  private
    FMyObject: IMyObject;
  public
/*
..
*/
  end;

You can see that the alternative requires more code typing. What we obtain for more work?

  • IMyObject can be implemented in DLL and used with different programming languages;
  • We obtain automatic memory management based on reference counting;
  • Automatic memory management makes possible fluent coding;
  • We can overload operators in TMyObject;
  • We get rid of all TObject overhead.

You may ask what about inheritance and polymorphism (late binding)? These are moved from classes (TMyObject) to interfaces (IMyObject), and the move makes coding more elastic. We now have separate inheritance of interfaces and implementations, and interfaces are always polymorphic (late bound).
You can notice that interfaces in Delphi are implemented using classes derived from TInterfacedObject but as I posted before this is not necessary – interfaces can be implemented in a more compact and efficient way.

And this closes the ring; TObject is not needed.

Consuming Delphi interfaces in Dephi and C++

4

An object-oriented DLL written in Delphi exports functions with parameters of interface type. A code consuming such DLL can use an interface reference directly, but a better way is to write a wrapper type which encapsulates an interface reference. Let us consider as an example a simple interface IBytes designed to work with byte arrays:

unit ITypes;

interface

type
  IBytes = interface
    function GetLength: Integer; stdcall;
    procedure Append(B: Byte); stdcall;
    procedure CopyTo(var C: IBytes); stdcall;
  end;

implementation

end.

The IBytes interface is implemented by the TByteObject class:

unit ByteObjects;

interface

uses ITypes;

type
  TByteObject = class(TInterfacedObject, IBytes)
    FBytes: array of Byte;
    function GetLength: Integer; stdcall;
    procedure Append(B: Byte); stdcall;
    procedure CopyTo(var C: IBytes); stdcall;
  end;

implementation

{ TByteObject }

procedure TByteObject.Append(B: Byte);
begin
  SetLength(FBytes, Length(FBytes) + 1);
  FBytes[Length(FBytes)]:= B;
end;

procedure TByteObject.CopyTo(var C: IBytes);
var
  Instance: TByteObject;

begin
  Instance:= TByteObject.Create;
  SetLength(Instance.FBytes, Length(FBytes));
  Move(Pointer(FBytes)^, Pointer(Instance.FBytes)^, Length(FBytes));
  C:= Instance;
end;

function TByteObject.GetLength: Integer;
begin
  Result:= Length(FBytes);
end;

end.

We implement the IBytes interface in DLL:

library TestDLL;

uses
  SysUtils,
  Classes,
  ITypes in 'ITypes.pas',
  ByteObjects in 'ByteObjects.pas';

procedure GetInterface(var I: IBytes); stdcall;
begin
  I:= TByteObject.Create;
end;

exports
  GetInterface;

{$R *.res}

begin
end.

The DLL exports the single function which creates instances of TByteObject class.

To consume the IBytes interface in Delphi we use an advanced record type to avoid the unnecessary overhead of Delphi classes:

unit ByteWrappers;

interface

uses Windows, ITypes;

type
  TGetInterface = procedure(var I: IBytes); stdcall;

var
  GetInterface: TGetInterface;

function LoadDll(const Name: string): Boolean;

type
  TMyBytes = record
  private
    FBytes: IBytes;
  public
    procedure Append(B: Byte);
    procedure CopyTo(var C: TMyBytes);
    function GetLength: Integer;
    procedure Free;
  end;

implementation

{ TMyBytes }

procedure TMyBytes.Append(B: Byte);
begin
  if (FBytes = nil) then GetInterface(FBytes);
  FBytes.Append(B);
end;

procedure TMyBytes.CopyTo(var C: TMyBytes);
begin
  if (FBytes = nil) then C.FBytes:= nil
  else FBytes.CopyTo(C.FBytes);
end;

procedure TMyBytes.Free;
begin
  FBytes:= nil;
end;

function TMyBytes.GetLength: Integer;
begin
  if (FBytes = nil) then Result:= 0
  else Result:= FBytes.GetLength;
end;

function LoadDll(const Name: string): Boolean;
var
  LibHandle: THandle;

begin
  LibHandle:= LoadLibrary(PChar(Name));
  if (LibHandle <> 0) then begin
    @GetInterface:= GetProcAddress(LibHandle, 'GetInterface');
    if @GetInterface <> nil then begin
      Result:= True;
      Exit;
    end;
    FreeLibrary(LibHandle);
  end;
  Result:= False;
end;

end.

And simple test application to be sure everything works as expected:

program Test;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ITypes in 'ITypes.pas',
  ByteWrappers in 'ByteWrappers.pas';

procedure TestInterface;
var
  Bytes1, Bytes2: TMyBytes;

begin
  Bytes1.Append(0);
  Bytes1.CopyTo(Bytes2);
  Bytes1.Append(0);
  Writeln(Bytes1.GetLength, ' -- ', Bytes2.GetLength);
end;

begin
  try
    ReportMemoryLeaksOnShutdown:= True;
    if LoadDll('TestDLL.dll')
      then TestInterface
      else Writeln('Can''t load TestDLL.dll');
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

So far so good; now we want to consume the above Delphi interface in a C++ structure (or a class – there is no difference between a C++ structure and a C++ class here). The solution is:

// ByteWrappers.hpp
#ifndef BYTEWRAPPERS_H_INCLUDED
#define BYTEWRAPPERS_H_INCLUDED

#include <string>

using namespace std;

typedef uint8_t Byte;
typedef int32_t Integer;

bool LoadDll(string Name);

class IBytes {
  public:
    virtual Integer __stdcall QueryInterface(void* riid, void** ppvObject) = 0;
    virtual Integer __stdcall AddRef() = 0;
    virtual Integer __stdcall Release() = 0;
    virtual Integer __stdcall GetLength() = 0;
    virtual void __stdcall Append(Byte B) = 0;
    virtual void __stdcall CopyTo(IBytes** C) = 0;
};

class MyBytes {
  private:
    IBytes* FBytes;
  public:
    MyBytes() : FBytes(NULL) {};    // default constructor
    MyBytes(const MyBytes& A)       // copy constructor
    {
    	FBytes = A.FBytes;
    	if (FBytes != NULL)
    	{
    		FBytes->AddRef();
    	}
    };

    ~MyBytes()                      // destructor
    {
  	    if (FBytes != NULL)
  	    {
  		    FBytes->Release();
  		    FBytes = NULL;
  	    }
    };

    MyBytes& operator= (const MyBytes& A)   // assignment
    {
        if (A.FBytes != NULL)
            A.FBytes->AddRef();
        if (FBytes != NULL)
            FBytes->Release();
        FBytes = A.FBytes;
        return *this;
    }

    void Free()
    {
        if (FBytes != NULL)
        {
            FBytes->Release();
            FBytes = NULL;
        }
    }

    void Append(Byte B);
    void CopyTo(MyBytes& C);
    Integer GetLength();
};

#endif // BYTEWRAPPERS_H_INCLUDED
// ByteWrappers.cpp
#include <windows.h>
#include "ByteWrappers.hpp"

typedef void(__stdcall *PGetInterface)(IBytes**);
PGetInterface GetInterface = 0;

void MyBytes::Append(Byte B)
{
    if (FBytes == NULL) GetInterface(&FBytes);
    FBytes->Append(B);
}

void MyBytes::CopyTo(MyBytes& C)
{
    if (FBytes == NULL) C.Free();
    else FBytes->CopyTo(&C.FBytes);
}

Integer MyBytes::GetLength()
{
    if (FBytes == NULL) return 0;
    else return FBytes->GetLength();
}

bool LoadDll(string Name)
{
    HINSTANCE LibHandle;

    LibHandle = LoadLibrary(Name.c_str());
    if (LibHandle != 0)
    {
        GetInterface = (PGetInterface)GetProcAddress(LibHandle, "GetInterface");
        if (GetInterface != NULL) return true;
        FreeLibrary(LibHandle);
    }
    return false;
}

Test application:

#include <iostream>
#include <string>
#include "ByteWrappers.hpp"

using namespace std;

void TestInterface(){
    MyBytes Bytes1;
    MyBytes Bytes2;

    Bytes1.Append(0);
    Bytes1.CopyTo(Bytes2);
    Bytes1.Append(0);
    cout << Bytes1.GetLength() << " -- " << Bytes2.GetLength() << endl;
}

int main()
{
    if (LoadDll("TestDLL.dll"))
        TestInterface();
    else
        cout << "Can't load TestDLL.dll" << endl;
    return 0;
}

Some details worth being mentioned:

  • Delphi interfaces are always derived from IUnknown; a corresponding pure abstract C++ class should also define IUnknown methods;
  • Delphi interface type is kind of a pointer to the corresponding C++ abstract class, so sometimes we need one more level of indirection in C++ code;
  • Delphi interface variables are always initialized to nil by the compiler; in C++ we need default constructor to implement the nil-initialization;
  • Delphi interfaces are automatically released (i.e. call IUnknown._Release method) when an interface variable goes out of scope; In C++ we implement the same functionality in destructor;
  • Interface assignment in Delphi implicitly calls _Addref and _Release methods of IUnknown; in C++ we overload the assignment operator to implement the interface assignment correctly;
  • C++ supports variable initialization like this:
        MyBytes Bytes1;
        Bytes1.Append(0);
        MyBytes Bytes2 = Bytes1;
    

    to implement it correctly in our case we need a copy constructor.

Delayed dynamic DLL loading

2

The problem: suppose you are writing a 3rd party library which uses an external DLL. This is the case when dynamic (explicit) DLL loading is preferable over static (implicit). Your library includes a load function which loads the DLL (by calling LoadLibrary and GetProcAddress functions) and now you have a dilemma – you can either warn the user that he should call the load function before using your library or you can call the load function yourself (in the initialization section of one of library units) so all a user should do is to place the DLL in the right location on disk. Both solutions have their pros and cons.

There is also an elegant solution that combines the best of both – you allow a user to load the DLL explicitly by calling the load function but if he did not done it the load function is called transparently when a DLL function is called first time. Here is an implementation example:

The DLL which exports 2 functions:

library DemoLib;

type
  TLoadResult = (LOAD_ERROR = -1, LOAD_OK = 0, LOAD_ALREADYLOADED = 1);

function GetValue(var Value: Integer): TLoadResult;
begin
  Value:= 42;
  Result:= LOAD_OK;
end;

function GetIsValid(AValue: Integer; var IsValid: Boolean): TLoadResult;
begin
  IsValid:= AValue = 42;
  Result:= LOAD_OK;
end;

exports
  GetValue,
  GetIsValid;

{$R *.res}

begin
end.

The load function:

unit LoadLib;

interface

type
  TLoadResult = (LOAD_ERROR = -1, LOAD_OK = 0, LOAD_ALREADYLOADED = 1);

type
  TGetValue = function(var Value: Integer): TLoadResult;
  TGetIsValid = function(AValue: Integer; var IsValid: Boolean): TLoadResult;

var
  GetValue: TGetValue;
  GetIsValid: TGetIsValid;

function LoadDemo(const Name: string = ''): TLoadResult;

implementation

uses Windows;

const
  LibName = 'DemoLib.dll';

function GetValueError(var Value: Integer): TLoadResult;
begin
  Result:= LOAD_ERROR;
end;

function GetIsValidError(AValue: Integer; var IsValid: Boolean): TLoadResult;
begin
  Result:= LOAD_ERROR;
end;

var
  LoadResult: TLoadResult = LOAD_OK;

function LoadDemo(const Name: string): TLoadResult;
var
  LibHandle: THandle;

begin
  if (LoadResult = LOAD_ALREADYLOADED) then begin
    Result:= LOAD_ALREADYLOADED;
    Exit;
  end;
  if Name = ''
    then LibHandle:= LoadLibrary(LibName)
    else LibHandle:= LoadLibrary(PChar(Name));
  if (LibHandle <> 0) then begin
    @GetValue:= GetProcAddress(LibHandle, 'GetValue');
    @GetIsValid:= GetProcAddress(LibHandle, 'GetIsValid');
    if (@GetValue <> nil) and (@GetIsValid <> nil) then begin
      LoadResult:= LOAD_ALREADYLOADED;
      Result:= LOAD_OK;
      Exit;
    end;
    FreeLibrary(LibHandle);
  end;
  @GetValue:= @GetValueError;
  @GetIsValid:= @GetIsValidError;
  LoadResult:= LOAD_ERROR;
  Result:= LOAD_ERROR;
end;

function GetValueStub(var Value: Integer): TLoadResult;
begin
  LoadDemo();
  Result:= GetValue(Value);
end;

function GetIsValidStub(AValue: Integer; var IsValid: Boolean): TLoadResult;
begin
  LoadDemo();
  Result:= GetIsValid(AValue, IsValid);
end;

initialization
  @GetValue:= @GetValueStub;
  @GetIsValid:= @GetIsValidStub;
end.

And the test application:

program TestLib;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  LoadLib in 'LoadLib.pas';

procedure Test;
var
  Value: Integer;

begin
  if GetValue(Value) <> LOAD_OK then
    raise Exception.Create('Load Error');
  Writeln(Value);
end;

begin
  try
    Test;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  ReadLn;
end.

Initially GetValue and GetIsValid procedural variables reference GetValueStub and GetIsValidStub functions which call the DLL load function first; after the DLL was loaded these variables reference either the DLL functions if the loading was successful or the error functions GetValueError and GetIsValidError respectively if the loading failed.