Recent

Author Topic: [SOLVED] Stack Overflow without decernable Reason  (Read 4967 times)

jamie

  • Hero Member
  • *****
  • Posts: 7763
Re: Stack Overflow without decernable Reason
« Reply #15 on: November 16, 2022, 06:35:53 pm »
I noticed you have no Constructor override or Destructor in the class?

are you actually creating the Class somewhere?
The only true wisdom is knowing you know nothing

MMarie

  • New Member
  • *
  • Posts: 49
  • Right, lets bodge this pisspot
    • Homepage
Re: Stack Overflow without decernable Reason
« Reply #16 on: November 16, 2022, 08:24:19 pm »
I noticed you have no Constructor override or Destructor in the class?

are you actually creating the Class somewhere?

Yes, just forgot to add the unit with the program directive.
i use arch btw

Thaddy

  • Hero Member
  • *****
  • Posts: 19262
  • Glad to be alive.
Re: Stack Overflow without decernable Reason
« Reply #17 on: November 16, 2022, 09:17:53 pm »
As I wrote in {$R+} mode and at compile time the compiler will show you where that stack overflow occurs, provided line info is also on.
My guess is that if you do that you will immediately see why the overflow occurs. It is dead simple.
If the overflow occurs at runtime, provided the above, the error information will also include the reason and the place where it occurred.
objects are fine constructs. You can even initialize them with constructors.

Zvoni

  • Hero Member
  • *****
  • Posts: 3398
Re: Stack Overflow without decernable Reason
« Reply #18 on: November 16, 2022, 09:30:15 pm »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12399
  • Debugger - SynEdit - and more
    • wiki
Re: Stack Overflow without decernable Reason
« Reply #19 on: November 16, 2022, 09:44:33 pm »
As I wrote in {$R+} mode and at compile time the compiler will show you where that stack overflow occurs, provided line info is also on.

He got a line, posted in the gdb frame info earlier:
Quote
Code: Text  [Select][+][-]
  1. eip = 0x415830 in PARSEASMPARAM (src/uUtil.pas:47); saved eip 0x414ede

If his posted units are complete and unmodified, then that is a "begin" of a procedure.

In the begin line, the "frame" gets initialized. And the code might allocate stack by modifying the stackpointer.

It would then be good to know the exact definition of all the types (params and result):
Code: Pascal  [Select][+][-]
  1.  function ParseASMParam(const AParam: String; const acceptableTypes: TParamTypes; var AInterfaceData: TInterfaceDataArr): TByteArray;
Maybe one of them adds lots of stack memory usage. (Though assuming they are sets and dyn array, that isn't likely)

I can't tell if the code can recurse... It does not look like that in the posted code. But There is no indication what TInterfaceData does....
Looking at how many calling frames there are, may also help.

And if nothing comes up from that, maybe the asm of the begin line...





Also not sure if I misread gdb output, or if there is something:
Code: Text  [Select][+][-]
  1. (gdb) x/x $esp
  2. 0x432a70:       0x00000000
  3. (gdb) info frame
  4. Stack level 0, frame at 0x142fa78:
  5.  eip = 0x415830 in PARSEASMPARAM (src/uUtil.pas:47); saved eip 0x414ede


If the value of esp is 0x432a70 => then haw can the frame be at 0x142fa78

Well the frame would be in the basepointer ebp. But that is a copy of the esp, before the size of the frame is added to the esp.
Then if esp is so far off, something went wrong.

Hence maybe the asm (and values of involved registers). The code in front of the eip 0x415830 should be changing the esp.

I just can't see why it would allocate that much. (hence maybe the definition of the params).




jamie

  • Hero Member
  • *****
  • Posts: 7763
Re: Stack Overflow without decernable Reason
« Reply #20 on: November 17, 2022, 01:57:43 am »
This is what I have found after some examinations.

The function ConCatByteArra or whatever it's named does this

 Funciton Name(Aarray:TByteArray......)
  Begin
    /.. Then it gets to the point to where it sets the length.
 
 SetLength(Array,......)

 After all of the code is done doing all of this

 the RESULT := aArray.

 I found that it looks like the compiler is stuffing the incoming array somewhere, maybe the stack? Because it is not pointing to the actual starting array.

 So maybe if the ConCat Function would do this instread
  ConCat...(Var aArray:TByteArray...
                 ^^
  I did some test, and I can tell you that changing the incoming array size in the function does not change the source of it, so this means the compiler must be making a copy of it.
The only true wisdom is knowing you know nothing

PascalDragon

  • Hero Member
  • *****
  • Posts: 6396
  • Compiler Developer
Re: Stack Overflow without decernable Reason
« Reply #21 on: November 17, 2022, 07:37:04 am »
Don't you have to set the Length of the Dynamic Array-Result before exiting?
Or is "Exit" doing it in the Background?

Exit([$D0, $00]) is equivalent to Result := [$D0, $00]; Exit which simply uses the dynamic array constructors introduced in FPC 3.2.0.

I found that it looks like the compiler is stuffing the incoming array somewhere, maybe the stack? Because it is not pointing to the actual starting array.

The RTL makes an implicit copy when SetLength is called and that is always on the heap.

  I did some test, and I can tell you that changing the incoming array size in the function does not change the source of it, so this means the compiler must be making a copy of it.

Dynamic arrays are Copy-on-Resize and with the SetLength the RTL will decouple the passed dynamic array variable from the original.

Two remarks not related to your issue:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2.   function IntToBytes(const AInt: Integer): TByteArray;
  3.   begin
  4.     exit([
  5.           AInt and $FF00000000000000, AInt and $00FF000000000000, AInt and $0000FF0000000000,
  6.           AInt and $000000FF00000000, AInt and $00000000FF000000, AInt and $0000000000FF0000,
  7.           AInt and $000000000000FF00, AInt and $00000000000000FF
  8.         ]);
  9.   end;

This will not produce the result you expect. This will result in arrays containing $00, $00, $00, $00, $00, $00, $00, $xx with the last Byte being taken from the value you passed in. To get the correct values you need to shift and then convert/mask them. E.g. Byte(AInt shr 56) for the first one, Byte(AInt shr 48) for the second one and so on.
Also an Integer is either 16- or 32-bit depending on the mode, but never 64-bit. So you could optimize this by setting the first four values to $00, because they will be $00 anyway. Or you can change the input type to Int64.

  function ConcatByteArrs(AArr1: TByteArray; const AArr2: TByteArray): TByteArray;
  var
    i: Integer;
  begin
    SetLength(AArr1, Length(AArr1) + Length(AArr2));
    for i := 0 to Length(AArr2)-1 do
      AArr1[i+Length(AArr2)] := AArr2;

    result := AArr1;
  end;

You can also use dest := Concat(dest, src) or - if you enable {$ModeSwitch ArrayOperators} directly after the $Mode directive: dest := dest + src.

MMarie

  • New Member
  • *
  • Posts: 49
  • Right, lets bodge this pisspot
    • Homepage
Re: Stack Overflow without decernable Reason
« Reply #22 on: November 17, 2022, 08:26:33 am »
This is what I have found after some examinations.

The function ConCatByteArra or whatever it's named does this

 Funciton Name(Aarray:TByteArray......)
  Begin
    /.. Then it gets to the point to where it sets the length.
 
 SetLength(Array,......)

 After all of the code is done doing all of this

 the RESULT := aArray.

 I found that it looks like the compiler is stuffing the incoming array somewhere, maybe the stack? Because it is not pointing to the actual starting array.

 So maybe if the ConCat Function would do this instread
  ConCat...(Var aArray:TByteArray...
                 ^^
  I did some test, and I can tell you that changing the incoming array size in the function does not change the source of it, so this means the compiler must be making a copy of it.

Even when changing it to a var I still get a ERangeError. Also the error occurs /before/ ConcatByteArrs is called in my case.
Heres the main unit and my input file in case anyone wants to test it exactly like me:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. {$R+} {$Q+} {$H+}
  3. program PRESDK;
  4.  
  5. uses SysUtils, uASM;
  6.  
  7. var
  8.   command: String;
  9.   assembler: TPREAssembler;
  10. begin
  11.   command := ParamStr(1);
  12.  
  13.   case command of
  14.     'asm': begin
  15.       assembler := TPREAssembler.Create;
  16.       assembler.Run(ParamStr(2));
  17.     end;
  18.   end;
  19. end.

Code: Text  [Select][+][-]
  1. .interface
  2.   use std
  3.  
  4. .start
  5.   cal test
  6.   cal stop
  7.  
  8. proc test
  9.   ld #std:SYS, #std:S_PRINT
  10.   ld #std:SYP, "Hello, World!"
  11.   sys
  12.  
  13. proc stop
  14.   ld #std:SYS, #std:S_EXIT
  15.   ld #std:SYP, #0
  16.   sys
i use arch btw

MMarie

  • New Member
  • *
  • Posts: 49
  • Right, lets bodge this pisspot
    • Homepage
Re: Stack Overflow without decernable Reason
« Reply #23 on: November 17, 2022, 08:30:55 am »
Two remarks not related to your issue:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2.   function IntToBytes(const AInt: Integer): TByteArray;
  3.   begin
  4.     exit([
  5.           AInt and $FF00000000000000, AInt and $00FF000000000000, AInt and $0000FF0000000000,
  6.           AInt and $000000FF00000000, AInt and $00000000FF000000, AInt and $0000000000FF0000,
  7.           AInt and $000000000000FF00, AInt and $00000000000000FF
  8.         ]);
  9.   end;

This will not produce the result you expect. This will result in arrays containing $00, $00, $00, $00, $00, $00, $00, $xx with the last Byte being taken from the value you passed in. To get the correct values you need to shift and then convert/mask them. E.g. Byte(AInt shr 56) for the first one, Byte(AInt shr 48) for the second one and so on.
Also an Integer is either 16- or 32-bit depending on the mode, but never 64-bit. So you could optimize this by setting the first four values to $00, because they will be $00 anyway. Or you can change the input type to Int64.

  function ConcatByteArrs(AArr1: TByteArray; const AArr2: TByteArray): TByteArray;
  var
    i: Integer;
  begin
    SetLength(AArr1, Length(AArr1) + Length(AArr2));
    for i := 0 to Length(AArr2)-1 do
      AArr1[i+Length(AArr2)] := AArr2;

    result := AArr1;
  end;

You can also use dest := Concat(dest, src) or - if you enable {$ModeSwitch ArrayOperators} directly after the $Mode directive: dest := dest + src.
Thanks, didn't think about the shifting or the fact that Freepascal supports Array Operators, thats really cool!
i use arch btw

bytebites

  • Hero Member
  • *****
  • Posts: 787
Re: Stack Overflow without decernable Reason
« Reply #24 on: November 17, 2022, 09:20:10 am »
Code: Pascal  [Select][+][-]
  1.         TInterfaceData = record
  2.       name: String;
  3.       path: String;
  4.       procNames: TStringDynArray;
  5.       procIdents: TIntegerArray;
  6.       constNames: TStringDynArray;
  7.       constVals: TByteArrayArray;
  8.     end;      
  9.  

Is procIdents dynamic array?

Thaddy

  • Hero Member
  • *****
  • Posts: 19262
  • Glad to be alive.
Re: Stack Overflow without decernable Reason
« Reply #25 on: November 17, 2022, 09:45:12 am »
As declared the answer is yes.
objects are fine constructs. You can even initialize them with constructors.

jamie

  • Hero Member
  • *****
  • Posts: 7763
Re: Stack Overflow without decernable Reason
« Reply #26 on: November 17, 2022, 12:47:45 pm »
Code: Pascal  [Select][+][-]
  1.  if (info.sline[1] = ';') then continue;

 If you are making assumptions that Info.Sline contains something after the readln.

 I believe a blank line in the file can generate an empty string and thus this would be an range error I guess.

Maybe you should do this
Code: Pascal  [Select][+][-]
  1. If (Info.Sline='')or(Info.Sline[1]=';') Then continue;
  2.   //^^^^^^^^
  3.  
The only true wisdom is knowing you know nothing

MMarie

  • New Member
  • *
  • Posts: 49
  • Right, lets bodge this pisspot
    • Homepage
Re: Stack Overflow without decernable Reason
« Reply #27 on: November 17, 2022, 12:52:09 pm »
Code: Pascal  [Select][+][-]
  1.  if (info.sline[1] = ';') then continue;

 If you are making assumptions that Info.Sline contains something after the readln.

 I believe a blank line in the file can generate an empty string and thus this would be an range error I guess.

Maybe you should do this
Code: Pascal  [Select][+][-]
  1. If (Info.Sline='')or(Info.Sline[1]=';') Then continue;
  2.   //^^^^^^^^
  3.  


Yep, that was the Range Error, but the Stack Overflow still persists
i use arch btw

bytebites

  • Hero Member
  • *****
  • Posts: 787
Re: Stack Overflow without decernable Reason
« Reply #28 on: November 17, 2022, 01:12:56 pm »
As declared the answer is yes.

Is it guess or fact?

Code: Pascal  [Select][+][-]
  1.             writeln(sizeof(TInterfaceData));
  2.             tmp := ParseASMParam(parameters[0], [prmByte], FInterfaceData); // Causes Stack Overflow, why???
  3.             tmp := ConcatByteArrs(tmp, ParseASMParam(parameters[1], [prmAll], FInterfaceData));
  4.             out := ConcatByteArrs(out, ConcatByteArrs([OP_LD], tmp));      
  5.  

1006633496

Zvoni

  • Hero Member
  • *****
  • Posts: 3398
Re: Stack Overflow without decernable Reason
« Reply #29 on: November 17, 2022, 01:26:30 pm »
As declared the answer is yes.

Is it guess or fact?

Code: Pascal  [Select][+][-]
  1.             writeln(sizeof(TInterfaceData));
  2.             tmp := ParseASMParam(parameters[0], [prmByte], FInterfaceData); // Causes Stack Overflow, why???
  3.             tmp := ConcatByteArrs(tmp, ParseASMParam(parameters[1], [prmAll], FInterfaceData));
  4.             out := ConcatByteArrs(out, ConcatByteArrs([OP_LD], tmp));      
  5.  

1006633496
The 3rd Argument of ParseASMParam is an Array, so it would be that Size times what??

Change it to Pointer, allocate Memory on the Heap, and pass the Pointer?
Kinda
Code: Pascal  [Select][+][-]
  1. TInterfaceData = record
  2.       name: String;
  3.       path: String;
  4.       procNames: TStringDynArray;
  5.       procIdents: TIntegerArray;
  6.       constNames: TStringDynArray;
  7.       constVals: TByteArrayArray;
  8.     end;
  9. PInterfaceData = ^TInterfaceData;
  10. PPInterfaceData = ^PInterfaceData;
  11.     //TInterfaceDataArr = array of TInterfaceData;
  12. .
  13. .
  14. .
  15. { Parsing Funcs }
  16.   function ParseASMParam(const AParam: String; const acceptableTypes: TParamTypes;AInterfaceData: PPInterfaceDataArr): TByteArray;
  17.  
  18.  
« Last Edit: November 17, 2022, 01:30:26 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

 

TinyPortal © 2005-2018