Watch, Follow, &
Connect with Us

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


Welcome, Guest
Guest Settings
Help

Thread: Using a class object without creating it


This question is answered.


Permlink Replies: 15 - Last Post: Mar 7, 2016 11:51 PM Last Post By: Bernd Maierhofer
Lars-Göran Ande...

Posts: 6
Registered: 2/22/15
Using a class object without creating it  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 3, 2016 3:33 AM
I have learned that you must create an object before using it but how is this possible?

unit Unit2;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
 
type
  TForm2 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form2: TForm2;
 
implementation
 
{$R *.dfm}
 
type
  TTest = class(TObject)
  private
    FMyField: integer;
  public
    function MyField: integer;
    procedure setMyfield(const aFld: integer);
  end;
 
procedure TForm2.Button1Click(Sender: TObject);
var
  Test: TTest;
begin
  Test.setMyfield(1954);
  label1.Caption := intToStr(Test.MyField);
end;
 
{ TTest }
 
function TTest.MyField: integer;
begin
  Result := FMyfield;
end;
 
 
procedure TTest.setMyfield(const aFld: integer);
begin
  FMyField := aFld;
end;
 
end.


It would be very interesting to have a correct explanation. I run XE6.
Dalija Prasnikar

Posts: 2,325
Registered: 11/9/99
Re: Using a class object without creating it
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 3, 2016 3:53 AM   in response to: Lars-Göran Ande... in response to: Lars-Göran Ande...
Lars-Göran Andersson wrote:
I have learned that you must create an object before using it but how is this possible?

unit Unit2;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
 
type
  TForm2 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form2: TForm2;
 
implementation
 
{$R *.dfm}
 
type
  TTest = class(TObject)
  private
    FMyField: integer;
  public
    function MyField: integer;
    procedure setMyfield(const aFld: integer);
  end;
 
procedure TForm2.Button1Click(Sender: TObject);
var
  Test: TTest;
begin
  Test.setMyfield(1954);
  label1.Caption := intToStr(Test.MyField);
end;
 
{ TTest }
 
function TTest.MyField: integer;
begin
  Result := FMyfield;
end;
 
 
procedure TTest.setMyfield(const aFld: integer);
begin
  FMyField := aFld;
end;
 
end.


It would be very interesting to have a correct explanation. I run XE6.

I don't have XE6 to test exactly what happens with that compiler, but above code
crashes immediately, when you click the button in XE4.

Effectively, your code corrupts memory by setting field value in uninitialized
object instance - it writes at random place in the memory. Actual, manifestations
of that corruption can vary from system to system and one Delphi compiler to another.

--
Dalija Prasnikar
https://twitter.com/dalijap
https://plus.google.com/+DalijaPrasnikar
Lars-Göran Ande...

Posts: 6
Registered: 2/22/15
Re: Using a class object without creating it  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 3, 2016 8:09 AM   in response to: Dalija Prasnikar in response to: Dalija Prasnikar
Well, that sounds serious as I have found such code in production but also it has worked for a long time it seems.
I just wonder how that could be and why no problem is reported when I compile and run this code.

It crashes in XE4 you say but apparently not in XE6. That sounds very strange.

I hope to get some more discussion about this although I feel that I need to fix this old code.

Thanks for your answer but I still want som more.

//larand54
Robert Triest

Posts: 687
Registered: 3/24/05
Re: Using a class object without creating it  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 3, 2016 8:17 AM   in response to: Lars-Göran Ande... in response to: Lars-Göran Ande...
It crashes in XE4 you say but apparently not in XE6. That sounds very strange.
And it also doesn't crash when you close the application?? Sure the app doesn't ignore exceptions?
Lars-Göran Ande...

Posts: 6
Registered: 2/22/15
Re: Using a class object without creating it  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 4, 2016 12:29 AM   in response to: Robert Triest in response to: Robert Triest
Robert Triest wrote:
It crashes in XE4 you say but apparently not in XE6. That sounds very strange.
And it also doesn't crash when you close the application?? Sure the app doesn't ignore exceptions?

Yes I'm sure this simple test program handle the exceptions correct, no fixes in the settings and that is also valid for the production program which is a huge one.

Look below on Peter Belows answer "Blind Luck" he called it - that's a good explanation :)

//Larand54

Edited by: Lars-Göran Andersson on Mar 4, 2016 12:30 AM
John Treder

Posts: 349
Registered: 8/2/02
Re: Using a class object without creating it  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 3, 2016 9:56 AM   in response to: Lars-Göran Ande... in response to: Lars-Göran Ande...
Lars-Göran Andersson wrote:

I have learned that you must create an object before using it but how is this possible?

unit Unit2;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
 
type
  TForm2 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form2: TForm2;
 
implementation
 
{$R *.dfm}
 
type
  TTest = class(TObject)
  private
    FMyField: integer;
  public
    function MyField: integer;
    procedure setMyfield(const aFld: integer);
  end;
 
procedure TForm2.Button1Click(Sender: TObject);
var
  Test: TTest;
begin
  Test.setMyfield(1954);
  label1.Caption := intToStr(Test.MyField);
end;
 
{ TTest }
 
function TTest.MyField: integer;
begin
  Result := FMyfield;
end;
 
 
procedure TTest.setMyfield(const aFld: integer);
begin
  FMyField := aFld;
end;
 
end.


It would be very interesting to have a correct explanation. I run XE6.

Two ways to do that. if the object is a temporary one that will only be used locally, you can do this:

procedure TForm2.Button1Click(Sender: TObject);
var
Test: TTest;
begin
Test := TTsest.Create; // create the object
try
Test.setMyfield(1954);
label1.Caption := intToStr(Test.MyField);
finally
Test.Free; // you must be sure to free a local object that you create
end;
end;

If your object is going to exist for the life of the form and be used in a number of places, you can create it in the form's OnCreate event and destroy in in the form's OnDestroy event.
You'll have to move the TTest type declaration to the interface section, above the form's type declaration.
Put a private field in the form's delaration: FTest: TTest;
Double click the events in the IDE. Fill in the TForm2.FormCreate event handler with: FTest := TTest.Create;
Fill in the TForm2.FormDestryo event handler with FTest.Free;
Then in the Button1Click handler you don't put a local variable, you just write
FTest.setMyField(1954);
label1.Caption := IntToStr(FTest.MyField);

--
don't Tred on me
Lars-Göran Ande...

Posts: 6
Registered: 2/22/15
Re: Using a class object without creating it  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 4, 2016 12:38 AM   in response to: John Treder in response to: John Treder

Two ways to do that. if the object is a temporary one that will only be used locally, you can do this:
procedure TForm2.Button1Click(Sender: TObject);
var
Test: TTest;
begin
Test := TTsest.Create; // create the object
try
Test.setMyfield(1954);
label1.Caption := intToStr(Test.MyField);
finally
Test.Free; // you must be sure to free a local object that you create
end;
end;

If your object is going to exist for the life of the form and be used in a number of places, you can create it in the form's OnCreate event and destroy in in the form's OnDestroy event.
You'll have to move the TTest type declaration to the interface section, above the form's type declaration.
Put a private field in the form's delaration: FTest: TTest;
Double click the events in the IDE. Fill in the TForm2.FormCreate event handler with: FTest := TTest.Create;
Fill in the TForm2.FormDestryo event handler with FTest.Free;
Then in the Button1Click handler you don't put a local variable, you just write
FTest.setMyField(1954);
label1.Caption := IntToStr(FTest.MyField);

--
don't Tred on me

Ok, thats correct but I alredy know this. I was just suprised when I found this bug in an old working program.
And that's why I created this simple program to se whats happends. I expected som crasch or so, but no, it worked.

But thank you for trying to help - that's good.

//Larand54
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Using a class object without creating it
Correct
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 3, 2016 10:13 AM   in response to: Lars-Göran Ande... in response to: Lars-Göran Ande...
Lars-Göran wrote:

I have learned that you must create an object before using it

Yes.

how is this possible?

You are invoking undefined behavior. Your 'Test' variable is uninitialized.
It will contain whatever random value already exists in memory at the
location the variable occupies. When you access FMyField, its offset within
the TTest class is added to the object pointer, and then that memory address
is accessed. Your code is roughly equivilent to the following logic under
the hood:

type
  TTest = class(TObject)
  private
    FMyField: integer;
  public
    //function MyField: integer;
    class function MyField(Self: TTest): integer; static;
    //procedure setMyfield(const aFld: integer);
    class procedure setMyfield(Self: TTest; const aFld: integer); static;
  end;
 
procedure TForm2.Button1Click(Sender: TObject);
var
  Test: TTest; // contains a RANDOM VALUE!
begin
  //Test.setMyfield(1954);
  TTest.setMyfield(Test, 1954);
  //label1.Caption := IntToStr(Test.MyField);
  label1.Caption := IntToStr(TTest.MyField(Test));
end;
 
//function TTest.MyField: integer;
class function TTest.MyField(Self: TTest): integer;
begin
  //Result := Self.FMyField;
  Result := PInteger(NativeUInt(Self) + OffsetOf(TTest, FMyField))^;
end;
 
//procedure TTest.setMyfield(const aFld: integer);
class procedure TTest.setMyfield(Self: TTest; const aFld: integer);
begin
  //Self.FMyField := aFld;
  PInteger(NativeUInt(Self) + OffsetOf(TTest, FMyField))^ := aFld;
end;


Since the 'Test' variable is uninitialized, the Self pointer being passed
to the class methods is random, and so the memory address used to access
FMyField is random. The code MAY crash, if the resulting memory address
is invalid. Or the the code MAY succeed, if the resulting memory address
is valid, but it will be access some random integer in some block of memory
you are not expecting. You simply don't know what will happen.

--
Remy Lebeau (TeamB)
Lars-Göran Ande...

Posts: 6
Registered: 2/22/15
Re: Using a class object without creating it  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 4, 2016 12:50 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Lars-Göran wrote:

I have learned that you must create an object before using it

Yes.

how is this possible?

You are invoking undefined behavior. Your 'Test' variable is uninitialized.
It will contain whatever random value already exists in memory at the
location the variable occupies. When you access FMyField, its offset within
the TTest class is added to the object pointer, and then that memory address
is accessed. Your code is roughly equivilent to the following logic under
the hood:

type
  TTest = class(TObject)
  private
    FMyField: integer;
  public
    //function MyField: integer;
    class function MyField(Self: TTest): integer; static;
    //procedure setMyfield(const aFld: integer);
    class procedure setMyfield(Self: TTest; const aFld: integer); static;
  end;
 
procedure TForm2.Button1Click(Sender: TObject);
var
  Test: TTest; // contains a RANDOM VALUE!
begin
  //Test.setMyfield(1954);
  TTest.setMyfield(Test, 1954);
  //label1.Caption := IntToStr(Test.MyField);
  label1.Caption := IntToStr(TTest.MyField(Test));
end;
 
//function TTest.MyField: integer;
class function TTest.MyField(Self: TTest): integer;
begin
  //Result := Self.FMyField;
  Result := PInteger(PNativeUInt(Self) + OffsetOf(TTest, FMyField))^;
end;
 
//procedure TTest.setMyfield(const aFld: integer);
class procedure TTest.setMyfield(Self: TTest; const aFld: integer);
begin
  //Self.FMyField := aFld;
  PInteger(PNativeUInt(Self) + OffsetOf(TTest, FMyField))^ := aFld;
end;


Since the 'Test' variable is uninitialized, the Self pointer being passed
to the class methods is random, and so the memory address used to access
FMyField is random. The code MAY crash, if the resulting memory address
is invalid. Or the the code MAY succeed, if the resulting memory address
is valid, but it will be access some random integer in some block of memory
you are not expecting. You simply don't know what will happen.

--
Remy Lebeau (TeamB)

Thanks a lot for this explanation.
I was a bit unsure if there had been som changes in Delphi that automatically fixed an initialized object or if it was just "Blind luck" as Peter named it.

But now I'm sure and it was as I suspected.

I have now fixed that old program so it runs more safe now.

//Larand54
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Using a class object without creating it  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 4, 2016 9:02 AM   in response to: Lars-Göran Ande... in response to: Lars-Göran Ande...
Lars-Göran wrote:

I was a bit unsure if there had been som changes in Delphi
that automatically fixed an initialized object

Nope.

or if it was just "Blind luck" as Peter named it.

Yes. Always has been. Now, in the case of mobile systems that use ARC for
objects, object pointers are auto-initialized to nil so reference counting
works correctly. But on desktop systems that don't use ARC for objects,
that is not the case.

--
Remy Lebeau (TeamB)
Peter Below

Posts: 1,227
Registered: 12/16/99
Re: Using a class object without creating it
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 3, 2016 10:15 AM   in response to: Lars-Göran Ande... in response to: Lars-Göran Ande...
Lars-Göran Andersson wrote:

I have learned that you must create an object before using it but how
is this possible?

Blind luck <g>. See my explanation further down.


{code}
unit Unit2;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.StdCtrls;

type
TForm2 = class(TForm)
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form2: TForm2;

implementation

{$R *.dfm}

type
TTest = class(TObject)
private
FMyField: integer;
public
function MyField: integer;
procedure setMyfield(const aFld: integer);
end;

procedure TForm2.Button1Click(Sender: TObject);
var
Test: TTest;

This local variable is not initialized by the compiler, so, at
run-time, it will contain a basically random value, which the code then
uses as the address of a TTest instance. whether writing to the object
field (which resides at an offset to the address contained in the Test
variable) results in an access violation or not depends on the address.
If it happens to point into a valid data block you get no access
violation, but you overwrite data somewhere in your application, which
usually has interesting consequences somewhere else in your application.

Local variables are allocated on the stack, and if they are not
initialized to specific values the variable will contain whatever
happended to be in the stack address used for the variable.

The compiler adds initialization code only for stack variables of
compiler-managed types, which are

- interfaces
- string types (ansistring, widestring, unicodestring)
- variants (and olevariants)
- dynamic arrays

These are all initialized to nil (or zero-filled for a variant). For
all other types you need to make sure to put a valid value into a stack
variable before you use it.


--
Peter Below
TeamB

Lars-Göran Ande...

Posts: 6
Registered: 2/22/15
Re: Using a class object without creating it  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 4, 2016 12:52 AM   in response to: Peter Below in response to: Peter Below
Peter Below wrote:
Lars-Göran Andersson wrote:

I have learned that you must create an object before using it but how
is this possible?

Blind luck <g>. See my explanation further down.


{code}
unit Unit2;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.StdCtrls;

type
TForm2 = class(TForm)
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form2: TForm2;

implementation

{$R *.dfm}

type
TTest = class(TObject)
private
FMyField: integer;
public
function MyField: integer;
procedure setMyfield(const aFld: integer);
end;

procedure TForm2.Button1Click(Sender: TObject);
var
Test: TTest;

This local variable is not initialized by the compiler, so, at
run-time, it will contain a basically random value, which the code then
uses as the address of a TTest instance. whether writing to the object
field (which resides at an offset to the address contained in the Test
variable) results in an access violation or not depends on the address.
If it happens to point into a valid data block you get no access
violation, but you overwrite data somewhere in your application, which
usually has interesting consequences somewhere else in your application.

Local variables are allocated on the stack, and if they are not
initialized to specific values the variable will contain whatever
happended to be in the stack address used for the variable.

The compiler adds initialization code only for stack variables of
compiler-managed types, which are

- interfaces
- string types (ansistring, widestring, unicodestring)
- variants (and olevariants)
- dynamic arrays

These are all initialized to nil (or zero-filled for a variant). For
all other types you need to make sure to put a valid value into a stack
variable before you use it.


--
Peter Below
TeamB


Thank's a lot - "Blind luck" that's a good name on it :)
//Larand54
Rudy Velthuis (...


Posts: 7,731
Registered: 9/22/99
Re: Using a class object without creating it  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 5, 2016 9:46 AM   in response to: Lars-Göran Ande... in response to: Lars-Göran Ande...
Lars-Göran Andersson wrote:

I have learned that you must create an object before using it but how
is this possible?

If you create an object, you don't create the code, you only reserve
space for the data of the class, zero it and the constructor may
initialize some or all of the data fields.

If your method does not access any of these fields, and are not virtual
or dynamic, it can run, even if the object does not exist yet.

But as soon as it tries to access any part of the object, or if it is
virtual or dynamic, things can go wrong (but don't have to). What
actually happens depends on which memory is accidently accessed. If it
belongs to the current process, you may get memory corruption or weird
results, and this can make something go wrong later on. If it doesn't
belong to the current process, you will most likely get an access
violation.

--
Rudy Velthuis http://www.rvelthuis.de

"In My Egotistical Opinion, most people's C programs should
be indented six feet downward and covered with dirt."
-- Blair P. Houghton.
Bernd Maierhofer

Posts: 161
Registered: 9/27/99
Re: Using a class object without creating it  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 6, 2016 11:39 PM   in response to: Lars-Göran Ande... in response to: Lars-Göran Ande...
You are sure, that in the real code the class has no static methods or
ancestors that have one?

brgds Bernd

"Lars-Göran Andersson" wrote in message
news:814576 at forums dot embarcadero dot com...

I have learned that you must create an object before using it but how is
this possible?

unit Unit2;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 
System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
 
type
  TForm2 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form2: TForm2;
 
implementation
 
{$R *.dfm}
 
type
  TTest = class(TObject)
  private
    FMyField: integer;
  public
    function MyField: integer;
    procedure setMyfield(const aFld: integer);
  end;
 
procedure TForm2.Button1Click(Sender: TObject);
var
  Test: TTest;
begin
  Test.setMyfield(1954);
  label1.Caption := intToStr(Test.MyField);
end;
 
{ TTest }
 
function TTest.MyField: integer;
begin
  Result := FMyfield;
end;
 
 
procedure TTest.setMyfield(const aFld: integer);
begin
  FMyField := aFld;
end;
 
end.


It would be very interesting to have a correct explanation. I run XE6.
Jacinto Franca

Posts: 10
Registered: 10/15/00
Re: Using a class object without creating it  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 7, 2016 4:58 AM   in response to: Lars-Göran Ande... in response to: Lars-Göran Ande...
El 3/3/2016 11:33 AM, Lars-Göran Andersson escribió:
I have learned that you must create an object before using it but how is this possible?

(...)
procedure TForm2.Button1Click(Sender: TObject);
var
   Test: TTest;
begin
   Test.setMyfield(1954);
   label1.Caption := intToStr(Test.MyField);
end;
(...)


It would be very interesting to have a correct explanation. I run XE6.

When you run that code Test has whatever value was in the stack when
TForm2.Button1Click was called.
When I run that, it has the address in the stack of a variable in the
Vcl.Controls.TControl.WndProc procedure that indirectly called
Button1Click. Test.setMyfield is called with that address as self, so
it assigns 1954 to the next variable of WndProc.
When you read Test.MyField, you read that variable too...
WndProc doesn't use that variable after Button1Click returns...
so it works... and nobody got hurt... but it was just good luck.

If you do this from other procedure where the caller didn't put in the
stack an address with unused space in the right place, you will get an
access violation or worst, corrupt some memory.

To corrupt some memory can be really bad... imagine trying to debug a
perfectly working code, in a completely unrelated part of your source
code where you got 'access violation at address $7A2', when a private
field, you know is always initialized and nobody else can change, has
the wrong value.

So don't ignore the warning:
[dcc32 Warning] Unit2.pas(40): W1036 Variable 'Test' might not have been
initialized
Bernd Maierhofer

Posts: 161
Registered: 9/27/99
Re: Using a class object without creating it  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 7, 2016 11:51 PM   in response to: Jacinto Franca in response to: Jacinto Franca
Ah, I remeber having this issue:

Class "Test" has been created and initialized somewhere else, but has not
been destroyed. Referencing the in another place class without creating gave
no error.

Bernd

"Jacinto Franca" wrote in message news:821814 at forums dot embarcadero dot com...

El 3/3/2016 11:33 AM, Lars-Göran Andersson escribió:
I have learned that you must create an object before using it but how is
this possible?

(...)
procedure TForm2.Button1Click(Sender: TObject);
var
   Test: TTest;
begin
   Test.setMyfield(1954);
   label1.Caption := intToStr(Test.MyField);
end;
(...)


It would be very interesting to have a correct explanation. I run XE6.

When you run that code Test has whatever value was in the stack when
TForm2.Button1Click was called.
When I run that, it has the address in the stack of a variable in the
Vcl.Controls.TControl.WndProc procedure that indirectly called
Button1Click. Test.setMyfield is called with that address as self, so
it assigns 1954 to the next variable of WndProc.
When you read Test.MyField, you read that variable too...
WndProc doesn't use that variable after Button1Click returns...
so it works... and nobody got hurt... but it was just good luck.

If you do this from other procedure where the caller didn't put in the
stack an address with unused space in the right place, you will get an
access violation or worst, corrupt some memory.

To corrupt some memory can be really bad... imagine trying to debug a
perfectly working code, in a completely unrelated part of your source
code where you got 'access violation at address $7A2', when a private
field, you know is always initialized and nobody else can change, has
the wrong value.

So don't ignore the warning:
[dcc32 Warning] Unit2.pas(40): W1036 Variable 'Test' might not have been
initialized
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02