Lazarus

Programming => General => Topic started by: paule32 on July 04, 2025, 02:07:39 pm

Title: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: paule32 on July 04, 2025, 02:07:39 pm
I have the following Codes, and I get a exception on Code Line:

Code: Pascal  [Select][+][-]
  1.   while REnum.MoveNext do
  2.   writeln('Value: ', intToStr(REnum.Current));

I don't can figure out what is wrong with the Code, so I can not fix it.

Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. {$modeswitch generics}
  3. unit Container;
  4.  
  5. interface
  6.  
  7. type
  8.   generic TList<T1> = class
  9.   private
  10.     FValue  : T1;
  11.     FTop    : specialize TList<T1>;
  12.     FBottom : specialize TList<T1>;
  13.     FPrev   : specialize TList<T1>;
  14.     FNext   : specialize TList<T1>;
  15.     FCount  : Integer;
  16.   type
  17.     Enumerator = class
  18.     private
  19.       FCurrent : specialize TList<T1>;
  20.       FHead    : specialize TList<T1>;
  21.     public
  22.       constructor Create(AList: specialize TList<T1>);
  23.       function GetCurrent: T1;
  24.       function MoveNext: Boolean;
  25.       property Current: T1 read GetCurrent;
  26.     end;
  27.     ReverseEnumerator = class
  28.     private
  29.       FCurrent: specialize TList<T1>;
  30.     public
  31.       constructor Create(AList: specialize TList<T1>);
  32.       function MoveNext: Boolean;
  33.       function GetCurrent: T1;
  34.       property Current: T1 read GetCurrent;
  35.     end;
  36.   public
  37.     constructor Create(AValue: T1);
  38.     procedure Add(AValue: T1);
  39.    
  40.     function GetEnumerator:               Enumerator;
  41.     function GetReverseEnumerator: ReverseEnumerator;
  42.   published
  43.     property Count: Integer read FCount;
  44.   end;
  45.  
  46.   generic TListVector<T1> = class(specialize TList<T1>)
  47.   public
  48.     constructor Create(AValue: T1);
  49.   end;
  50.  
  51.   generic TMap<T1, T2> = class
  52.   private
  53.     FValue1 : T1;
  54.     FValue2 : T2;
  55.     FCount  : Integer;
  56.   public
  57.     constructor Create(AValue1: T1; AValue2: T2);
  58.   end;
  59.  
  60. implementation
  61.  
  62. { TListEnumerator }
  63. constructor TList.Enumerator.Create(AList: specialize TList<T1>);
  64. begin
  65.   inherited Create;
  66.   FCurrent := nil;
  67.   FHead := AList.FTop;
  68. end;
  69.  
  70. function TList.Enumerator.MoveNext: Boolean;
  71. begin
  72.   if FCurrent = nil then
  73.   FCurrent := FHead else
  74.   FCurrent := FCurrent.FNext;
  75.  
  76.   result   := FCurrent <> nil;
  77. end;
  78.  
  79. function TList.Enumerator.GetCurrent: T1;
  80. begin
  81.   Result := FCurrent.FValue;
  82. end;
  83.  
  84.  
  85. { TListReverseEnumerator }
  86. constructor TList.ReverseEnumerator.Create(AList: specialize TList<T1>);
  87. begin
  88.   inherited Create;
  89.   FCurrent := AList.FBottom; // Beginne ganz unten
  90. end;
  91.  
  92. function TList.ReverseEnumerator.MoveNext: Boolean;
  93. begin
  94.   Result := FCurrent <> nil;
  95.   if Result then
  96.   FCurrent := FCurrent.FPrev;
  97. end;
  98.  
  99. function TList.ReverseEnumerator.GetCurrent: T1;
  100. begin
  101.   Result := FCurrent.FValue;
  102. end;
  103.  
  104.  
  105. { TListVector }
  106. constructor TListVector.Create(AValue: T1);
  107. begin
  108.   inherited Create(AValue);
  109. end;
  110.  
  111.  
  112. { TList }
  113. constructor TList.Create(AValue: T1);
  114. begin
  115.   inherited Create;
  116.   FValue  := AValue;
  117.  
  118.   FTop    := self;
  119.   FBottom := self;
  120.   FNext   := nil;
  121.  
  122.   FCount  := 1;
  123. end;
  124.  
  125. procedure TList.Add(AValue: T1);
  126. var
  127.   tmp: specialize TList<T1>;
  128. begin
  129.   tmp := TList.Create(AValue);
  130.   FBottom.FNext := tmp;
  131.   FBottom       := tmp;
  132.  
  133.   inc(FCount);
  134. end;
  135.  
  136. function TList.GetEnumerator:                     Enumerator; begin result :=        Enumerator.Create(Self); end;
  137. function TList.GetReverseEnumerator: TList.ReverseEnumerator; begin result := ReverseEnumerator.Create(Self); end;
  138.  
  139. constructor TMap.Create(AValue1: T1; AValue2: T2);
  140. begin
  141.   inherited Create;
  142. end;
  143.  
  144. end.

Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. {$M-}
  3. {$define DLLIMPORT}
  4. program test;
  5.  
  6. uses Container;
  7.  
  8. type
  9.   TVector        = specialize TListVector< Integer >;
  10.   TVectorReverse = TVector.ReverseEnumerator;
  11. var
  12.   V     : TVector;
  13.   REnum : TVectorReverse;
  14.  
  15. begin
  16.   V := TVector.Create(12);
  17.   V.Add(2);
  18.   V.Add(3);
  19.   V.Add(4);
  20.  
  21.   REnum := V.GetReverseEnumerator;
  22.   writeln('reeee');
  23.   while REnum.MoveNext do
  24.   writeln('Value: ', intToStr(REnum.Current));
  25.  
  26.   REnum.Free;
  27.   V.Free;
  28. end.
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: Zvoni on July 04, 2025, 02:14:44 pm
And the Text of the Exception is a State-Secret?
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: paule32 on July 04, 2025, 02:18:11 pm
no, not a Secret  ;D
It is a message from fibonacci s Memory Manager:

T:\a>test.exe
DLL attach: ok
start
syswin_x64_exception_handler
signals_exception_handler
exrec^.ExceptionCode = 20970608
press <enter>...
syswin_x64_exception_handler
signals_exception_handler
exrec^.ExceptionCode = 0
press <enter>...
syswin_x64_exception_handler
signals_exception_handler
exrec^.ExceptionCode = 4210160
press <enter>...
syswin_x64_exception_handler
signals_exception_handler
exrec^.ExceptionCode = 0
press <enter>...
T:\a>
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: Zvoni on July 04, 2025, 02:30:00 pm
I'm surprised this compiles
Code: Pascal  [Select][+][-]
  1. type
  2.   ..
  3.   TVectorReverse = TVector.ReverseEnumerator;

Because the Type "ReverseEnumerator" is in the Private Section of
generic TList<T1> = class
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: paule32 on July 04, 2025, 03:01:53 pm
I get this:

Code: Bash  [Select][+][-]
  1. Type "apropos word" to search for commands related to "word"...
  2. Reading symbols from test.exe...
  3. (No debugging symbols found in test.exe)
  4. (gdb) r
  5. Starting program: T:\a\test.exe
  6. [New Thread 12956.0x4f7c]
  7. [New Thread 12956.0x32b0]
  8. [New Thread 12956.0x43a4]
  9. DLL attach: ok
  10. start
  11. reeee
  12. Value:
  13. Thread 1 received signal SIGSEGV, Segmentation fault.
  14. 0x0000000100001494 in P$TEST$_$TLIST$1$CRC9F312717_$_REVERSEENUMERATOR_$__$$_GETCURRENT$$LONGINT ()
  15. (gdb) bt
  16. #0  0x0000000100001494 in P$TEST$_$TLIST$1$CRC9F312717_$_REVERSEENUMERATOR_$__$$_GETCURRENT$$LONGINT ()
  17. #1  0x0000000100001bf1 in main ()
  18. (gdb)
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: Warfley on July 04, 2025, 07:57:45 pm
Look at:
Code: Pascal  [Select][+][-]
  1. function TList.ReverseEnumerator.MoveNext: Boolean;
  2. begin
  3.   Result := FCurrent <> nil;
  4.   if Result then
  5.   FCurrent := FCurrent.FPrev;
  6. end;

What happens if FCurrent is the first element? Result is true because it's the first element. Then FCurrent is set to the prev which is nil. So it returns true as if FCurrent contains an element but you overwrote it with nil. So when you dereference it, it fails.

Build it exactly the same as the forward enumerator:
Code: Pascal  [Select][+][-]
  1. constructor TList.ReverseEnumerator.Create(AList: specialize TList<T1>);
  2. begin
  3.   inherited Create;
  4.   FCurrent := nil;
  5.   FHead := AList.FBottom;
  6. end;
  7.  
  8. function TList.ReverseEnumerator.MoveNext: Boolean;
  9. begin
  10.   if FCurrent = nil then
  11.   FCurrent := FHead else
  12.   FCurrent := FCurrent.FPrev;
  13.  
  14.   result   := FCurrent <> nil;
  15. end;
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: Thaddy on July 04, 2025, 08:18:27 pm
I'm surprised this compiles
If private in the same unit that is supposed to compile. private has unit scope.
Strict private does not compile. Strict private has class/record/object scope.

(The cause is a mistake at Borland later sold as a feature or what we call "Delphi compatibility")
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: paule32 on July 04, 2025, 08:27:11 pm
after made the modifications, I get:

Fatal: Internal error 2006012304
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: Thaddy on July 04, 2025, 08:35:53 pm
Can you still not grep the compiler sources and investigate why the symtable stack is not assigned?
Because that's where that internal error comes from:
Code: Pascal  [Select][+][-]
  1.     function TSymtablestack.top:TSymtable;
  2.       begin
  3.         if not assigned(stack) then
  4.           internalerror(2006012304);
  5.         result:=stack^.symtable;
  6.       end;
Which took two seconds to find.  >:D
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: paule32 on July 04, 2025, 08:46:47 pm
sorry for this - I am not a pro - I am a Hobbit.
and what tells me ?
that the FPC don't push a Symbol to the Symbol Stack ?

what has this to do with my Application ?
It is a FPC Problem.

I compiled the 3.3.1 FPC Version, and there is the Fatal;
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: Thaddy on July 04, 2025, 09:00:48 pm
This particular stack is not a CPU stack. It is a software stack that evaluates all kind of compiler structures in LIFO (a stack) order. This is vital to evaluate blocks in correct order: begin begin try finally end; end;
A stack will ensure all blocks are evaluated in the right order.
For your aspirations it is vital that you can find the internal errors on your own.
Internal errors have no duplicates, so the first and only hit is from where you investigate.
In this case you should find out why this stack is not assigned, most likely because you deleted or skipped too much from the system unit or the code generation part in the compiler itself.

And plz don't confuse us with two posts that mention the same internal error.
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: Zvoni on July 04, 2025, 09:33:46 pm
I'm surprised this compiles
If private in the same unit that is supposed to compile. private has unit scope.
Strict private does not compile. Strict private has class/record/object scope.

(The cause is a mistake at Borland later sold as a feature or what we call "Delphi compatibility")
Look closely.
That type is defined in unit container (upper code), which he uses in his program (lower code) and tries to access there in the type section
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: Warfley on July 05, 2025, 12:11:18 am
I compiled the 3.3.1 FPC Version, and there is the Fatal;
3.3.1 is not a version, its the development branch that changes daily and might introduce new bugs or fix bugs on a daily basis.
Have you updated your installation and checked if the bug persists? If so best file a bug report in the gitlab.
Additionally you should check if the bug is also in the last released version (3.2.2 or 3.2.4rc1), if not better stick to the stable releases anyway.
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: jamie on July 05, 2025, 12:15:23 am
Looking at this and having some sort of compiler understanding, I don't think this is possible without the compiler creating some limit of nesting.
Code: Pascal  [Select][+][-]
  1. type
  2.   generic TList<T1> = class
  3.   private
  4.     FValue  : T1;
  5.     FTop    : specialize TList<T1>;
  6.     FBottom : specialize TList<T1>;
  7.     FPrev   : specialize TList<T1>;
  8.     FNext   : specialize TList<T1>;
  9.     FCount  : Integer;
  10.   type
  11.     Enumerator = class
  12. ......
  13.  

 So, when the TList<T1> gets specialized somewhere, it builds a type from the template but, it encounters another specialize of itself before the current template is completed so it thus goes out and specializes the inner type, which by the way is receiving the same type. This in turn would repeat the cycle until you run out of something.
  Now I suppose if the compiler was smart enough it could determine that this is just a class and is the same as the parent so thus only assume a CLASS at that point and continue to assemble the parent template.

 I am not sure if the compiler can figure that out without running out of space trying to assemble a type.

Jamie


Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: paule32 on July 05, 2025, 01:19:44 pm
I download and compile Version:
- FPC 3.2.2
- FPC 3.3.1


The following Version works (no compile/Fatal Error):
- FPC 3.2.2    ok
- FPC 3.3.1
    nok

I used the same Code as for my first Posting.
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: paule32 on July 05, 2025, 02:55:34 pm
to clearify my problem:   I have it done.

The Problem was more in my Logic, so sorry about blame about FPC.
I get in touch with an overflow problem where Memory points to nowhere.

Here is the working Source Code for "Container.PAS" :

Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. {$modeswitch generics}
  3. unit Container;
  4.  
  5. interface
  6.  
  7. type
  8.   generic TList<T1> = class
  9.   private
  10.     FValue  : T1;
  11.     FTop    : specialize TList<T1>;
  12.     FBottom : specialize TList<T1>;
  13.     FPrev   : specialize TList<T1>;
  14.     FNext   : specialize TList<T1>;
  15.     FCount  : Integer;
  16.   type
  17.     Enumerator = class
  18.     private
  19.       FCurrent : specialize TList<T1>;
  20.       FHead    : specialize TList<T1>;
  21.     public
  22.       constructor Create(AList: specialize TList<T1>);
  23.       function GetCurrent: T1;
  24.       function MoveNext: Boolean;
  25.       property Current: T1 read GetCurrent;
  26.     end;
  27.     ReverseEnumerator = class
  28.     private
  29.       FCurrent: specialize TList<T1>;
  30.       FStart  : Boolean;
  31.     public
  32.       constructor Create(AList: specialize TList<T1>);
  33.       function MoveNext: Boolean;
  34.       function GetCurrent: T1;
  35.       property Current: T1 read GetCurrent;
  36.     end;
  37.   public
  38.     constructor Create(AValue: T1);
  39.     procedure Add(AValue: T1);
  40.    
  41.     function GetEnumerator:               Enumerator;
  42.     function GetReverseEnumerator: ReverseEnumerator;
  43.   published
  44.     property Count: Integer read FCount;
  45.   end;
  46.  
  47.   generic TListVector<T1> = class(specialize TList<T1>)
  48.   public
  49.     constructor Create(AValue: T1);
  50.   end;
  51.  
  52.   generic TMap<T1, T2> = class
  53.   private
  54.     FValue1 : T1;
  55.     FValue2 : T2;
  56.     FCount  : Integer;
  57.   public
  58.     constructor Create(AValue1: T1; AValue2: T2);
  59.   end;
  60.  
  61. implementation
  62.  
  63. { TListEnumerator }
  64. constructor TList.Enumerator.Create(AList: specialize TList<T1>);
  65. begin
  66.   inherited Create;
  67.   FCurrent := nil;
  68.   FHead := AList.FTop;
  69. end;
  70.  
  71. function TList.Enumerator.MoveNext: Boolean;
  72. begin
  73.   if FCurrent = nil then
  74.   FCurrent := FHead else
  75.   FCurrent := FCurrent.FNext;
  76.  
  77.   result   := FCurrent <> nil;
  78. end;
  79.  
  80. function TList.Enumerator.GetCurrent: T1;
  81. begin
  82.   Result := FCurrent.FValue;
  83. end;
  84.  
  85.  
  86. { TListReverseEnumerator }
  87. constructor TList.ReverseEnumerator.Create(AList: specialize TList<T1>);
  88. begin
  89.   inherited Create;
  90.   FCurrent := AList.FBottom; // Beginne ganz unten
  91.   FStart   := false;
  92. end;
  93.  
  94. function TList.ReverseEnumerator.MoveNext: Boolean;
  95. begin
  96.   if not FStart then
  97.   begin
  98.     FStart := true;
  99.     result := FCurrent <> nil;
  100.   end else
  101.   begin
  102.     if FCurrent <> nil then
  103.     FCurrent := FCurrent.FPrev;
  104.     result   := FCurrent <> nil;
  105.   end;
  106. end;
  107.  
  108. function TList.ReverseEnumerator.GetCurrent: T1;
  109. begin
  110.   Result := FCurrent.FValue;
  111. end;
  112.  
  113.  
  114. { TListVector }
  115. constructor TListVector.Create(AValue: T1);
  116. begin
  117.   inherited Create(AValue);
  118. end;
  119.  
  120.  
  121. { TList }
  122. constructor TList.Create(AValue: T1);
  123. begin
  124.   inherited Create;
  125.   FValue  := AValue;
  126.  
  127.   FTop    := self;
  128.   FBottom := self;
  129.   FNext   := nil;
  130.  
  131.   FCount  := 1;
  132. end;
  133.  
  134. procedure TList.Add(AValue: T1);
  135. var
  136.   tmp: specialize TList<T1>;
  137. begin
  138.   tmp := TList.Create(AValue);
  139.   tmp.FPrev     := FBottom;
  140.  
  141.   FBottom.FNext := tmp;
  142.   FBottom       := tmp;
  143.  
  144.   inc(FCount);
  145. end;
  146.  
  147. function TList.GetEnumerator:                     Enumerator; begin result :=        Enumerator.Create(Self); end;
  148. function TList.GetReverseEnumerator: TList.ReverseEnumerator; begin result := ReverseEnumerator.Create(Self); end;
  149.  
  150. constructor TMap.Create(AValue1: T1; AValue2: T2);
  151. begin
  152.   inherited Create;
  153. end;
  154.  
  155. end.

When you would like to use it, there is the below Source:

Code: Pascal  [Select][+][-]
  1. type
  2.   TVector        = specialize TListVector< Integer >;
  3.   TVectorReverse = TVector.ReverseEnumerator;
  4.  
  5. var
  6.   V     : TVector;
  7.   REnum : TVectorReverse;
  8.  
  9. var
  10.   item: Integer;
  11.  
  12. begin
  13.   V := TVector.Create(12);
  14.   V.Add(2);
  15.   V.Add(3);
  16.   V.Add(4);
  17.  
  18.   for item in V do
  19.   writeln('Value: ', IntToStr(item));
  20.  
  21.   REnum := V.GetReverseEnumerator;
  22.   while REnum.MoveNext do
  23.   writeln('Value: ', intToStr(REnum.Current));
  24.  
  25.   REnum.Free;
  26.   V.Free;
  27. end.

compiled, you will get the follow Output:

Code: Bash  [Select][+][-]
  1. Value: 12
  2. Value: 2
  3. Value: 3
  4. Value: 4
  5.  
  6. Value: 4
  7. Value: 3
  8. Value: 2
  9. Value: 12

So, Problem solved.
Thanks for all your Hints...
Title: Re: FPC 3.2.2 - nested Class and Generic Class - Memory Problem ?
Post by: Thaddy on July 05, 2025, 03:52:29 pm
That's is exactly what I told you. Then it works. But why so many threads on the same subject?
Should we just call the threads Paule32?
TinyPortal © 2005-2018