Recent

Author Topic: is this code correct?  (Read 469 times)

ginoo

  • Full Member
  • ***
  • Posts: 166
is this code correct?
« on: May 16, 2026, 03:46:50 pm »
I ask you too, is this assignment PTest(@ClasseTest.Test)^.Valore:=20 correct?

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{H+}
  4.  
  5. uses
  6.   SysUtils;
  7.  
  8. type
  9.   TTest = record
  10.       Valore: integer;
  11.   end;
  12.   PTest = ^TTest;
  13.  
  14.   TClasseTest = class
  15.     private
  16.       FTest: TTest;
  17.     public
  18.       property Test: TTest read FTest write FTest;
  19.   end;
  20.  
  21. var
  22.   ClasseTest: TClasseTest;
  23. begin
  24.   ClasseTest := TClasseTest.Create;
  25.   PTest(@ClasseTest.Test)^.Valore:=20;
  26.   WriteLn(ClasseTest.Test.Valore);
  27.   ClasseTest.Free;
  28.   Readln;
  29. end.  
  30.  

jamie

  • Hero Member
  • *****
  • Posts: 7765
Re: is this code correct?
« Reply #1 on: May 16, 2026, 04:21:03 pm »
Yes, that looks like it would work however, Classes are already pointers, what you did was made an indirect pointer to a pointer.

You specified the pointer address which is on the local stack that points to the Pointer of the class instance.

 Something like that You should not be passing the address to other remote functions unless you call that function within the function as a reference not to be stored elsewhere once you leave the body the of the main function.

 In other words, passing that to a function to be used and stored elsewhere is not a good plan, any passing of that pointer to a pointer should be intermediate and flagged as unusable once your main function exits.

I wanted to add that in C++ land, Classes are copied to parameters using the default copy constructor of the class if there is no REFERENCE indicated, like USING VAR or OUT in pascal. So, this means you wouldn't need to worry too much since it was a generated copy however, that remote function needs to clean it up.


Jamie.
« Last Edit: May 16, 2026, 04:23:52 pm by jamie »
The only true wisdom is knowing you know nothing

LemonParty

  • Hero Member
  • *****
  • Posts: 530
Re: is this code correct?
« Reply #2 on: May 16, 2026, 09:28:46 pm »
Someone on this forum told me that class fields can be rearranged. So I assume those tricks dangerous.
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

n7800

  • Hero Member
  • *****
  • Posts: 709
  • Lazarus IDE contributor
    • GitLab profile

Thaddy

  • Hero Member
  • *****
  • Posts: 19268
  • Glad to be alive.
Re: is this code correct?
« Reply #4 on: May 17, 2026, 06:42:22 am »
The code works, but is technically dubious, indeed, the class field reordering can give you wrong access pointers. If you want to prevent this you can turn that off:
Code: Pascal  [Select][+][-]
  1. {$optimization orderfields-}
If you need to access strict private or private fields like you do above, the code is not good in the first place.
It counts towards implementation detail, so is not future proof as well.
A better, safer way is to use a proxy class definition with higher visibilities. (a.k.a. a class cracker)
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2.  
  3. type
  4.   TTest = record
  5.       Valore: integer;
  6.   end;
  7.   PTest = ^TTest;
  8.  
  9.   TClasseTest = class
  10.     private
  11.       FTest: TTest;
  12.     public
  13.       property Test: TTest read FTest write FTest;
  14.   end;
  15.  
  16.   TTestCracker = class
  17.   public
  18.       FTest: TTest;
  19.       property Test: TTest read FTest write FTest;
  20.   end;
  21.  
  22. var
  23.   ClasseTest: TClasseTest;
  24. begin
  25.   ClasseTest := TClasseTest.Create;
  26.   TTestCracker(ClasseTest).FTest.Valore:=20;  //direct field access
  27.   WriteLn(ClasseTest.Test.Valore);
  28.   ClasseTest.Free;
  29.   Readln;
  30. end.
This will also work when reorderfields is on. (reordering would be the same)
If that solution is any good? Basically same answer: if you need to access private class fields your code is wrong.
But a class cracker is a cleaner solution.

If it was just the property access, the solution is much simpler:
Code: Pascal  [Select][+][-]
  1. var
  2.   ClasseTest: TClasseTest;
  3.   T:TTest;
  4. begin
  5.   ClasseTest := TClasseTest.Create;
  6.   T.Valore := 40;
  7.   ClasseTest.Test:=T;
  8.   WriteLn(ClasseTest.Test.Valore);
  9.   ClasseTest.Free;
  10.   Readln;
  11. end.
Use the proper type to write to the property, so use a TTest.
You can not write to the property field value directly, you must use a TTest variable because that is what you defined....
« Last Edit: May 17, 2026, 07:21:46 am by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

ginoo

  • Full Member
  • ***
  • Posts: 166
Re: is this code correct?
« Reply #5 on: May 17, 2026, 07:34:45 am »
@Thaddy

The ClassCracker is interesting, but there is a way to do this?

Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2.  
  3. type
  4.   TTest = record
  5.       Valore: integer;
  6.   end;
  7.   PTest = ^TTest;
  8.  
  9.   TClasseTest = class
  10.     private
  11.       ugo : String;
  12.       FTest: TTest;
  13.       ugo2 : String;
  14.     public
  15.       property Test: TTest read FTest write FTest;
  16.   end;
  17.  
  18.   TTestCracker = class
  19.   public
  20.       FTest: TTest;
  21.       property Test: TTest read FTest write FTest;
  22.   end;
  23.  
  24. var
  25.   ClasseTest: TClasseTest;
  26. begin
  27.   ClasseTest := TClasseTest.Create;
  28.   TTestCracker(ClasseTest).FTest.Valore:=20;  //direct field access
  29.   WriteLn(ClasseTest.Test.Valore);
  30.   ClasseTest.Free;
  31.   Readln;
  32. end.      
  33.  
  34.  

Error: SIGSEGV     GPF


In other words, in the `classcracker` class, should I include only `FTest: TTest` and not the other variables?


Thaddy

  • Hero Member
  • *****
  • Posts: 19268
  • Glad to be alive.
Re: is this code correct?
« Reply #6 on: May 17, 2026, 09:11:30 am »
Of course: the class cracker should be exactly the same layout as the class....
That is obvious....
Code: Pascal  [Select][+][-]
  1.   TTestCracker = class
  2.   public
  3.     ugo : String;
  4.     FTest: TTest;
  5.     ugo2 : String;
  6.     property Test: TTest read FTest write FTest;
  7.   end;
Now it will obviously work....
A class cracker needs ALL fields exactly the same.
And because of that it is not vulnarable for reordering. Because it will be reordered the same. (Currently)

Stays bad code if you need it.
« Last Edit: May 17, 2026, 09:18:10 am by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

Lutz Mändle

  • Jr. Member
  • **
  • Posts: 99
Re: is this code correct?
« Reply #7 on: May 17, 2026, 01:28:25 pm »
The expression @ClasseTest.Test gives the address of the field FTest. How can this affected by class field reordering?

LemonParty

  • Hero Member
  • *****
  • Posts: 530
Re: is this code correct?
« Reply #8 on: May 17, 2026, 02:08:55 pm »
The expression @ClasseTest.Test gives the address of the field FTest. How can this affected by class field reordering?
Oh! I didn't notice. Line
Code: Pascal  [Select][+][-]
  1. PTest(@ClasseTest.Test)^.Valore:=20;
should work for sure. But this line has the same effect like:
Code: Pascal  [Select][+][-]
  1. ClasseTest.Test.Valore:=20;
What the point to do that?
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

Thaddy

  • Hero Member
  • *****
  • Posts: 19268
  • Glad to be alive.
Re: is this code correct?
« Reply #9 on: May 17, 2026, 03:23:29 pm »
The expression @ClasseTest.Test gives the address of the field FTest. How can this affected by class field reordering?
Not directly, but if you only handle offsets for the fields things go wrong. The point is that you can not assume that the field layout is as is written.
« Last Edit: May 17, 2026, 03:38:09 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

 

TinyPortal © 2005-2018