Recent

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

MMarie

  • New Member
  • *
  • Posts: 49
  • Right, lets bodge this pisspot
    • Homepage
[SOLVED] Stack Overflow without decernable Reason
« on: November 16, 2022, 03:14:45 pm »
Hi all,
I'm currently working on implementing a "Compiler" for a custom language and have been running into a Stack Overflow without a decernable reason. I'm not doing recursions and have checked that, and even upping the Stack-Size still doesn't help.

(This is my first post so please just let me know if I have done anything wrong with Formatting or anything)

Here is my code
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. unit uASM;
  3.  
  4. interface
  5.  
  6.   uses StrUtils, SysUtils, Types, uPRECodes, uUtil;
  7.  
  8.   type
  9.     TInformation = record
  10.       path, outpath: String;
  11.       _file: TextFile;
  12.       cline: Integer;
  13.       sline: String;
  14.     end;
  15.     TPREAssembler = class
  16.     private
  17.       FInterfaceData: TInterfaceDataArr;
  18.  
  19.       { FeEc 16-11-2022: idc that this violates my own Styleguide, its gonna get changed later on }
  20.       info: TInformation;
  21.     public
  22.       function Assemble: TByteArray;
  23.       procedure Run(const AFile: String);
  24.     end;
  25.  
  26. implementation
  27.   function TPREAssembler.Assemble: TByteArray;
  28.   var
  29.     instruction: String;
  30.     tmp, out: TByteArray;
  31.     split, parameters: Types.TStringDynArray;
  32.   begin
  33.     out := [];
  34.  
  35.     while not eof(info._file) do
  36.     begin
  37.       info.cline := info.cline + 1;
  38.       Readln(info._file, info.sline);
  39.       info.sline := Trim(info.sline);
  40.  
  41.       // Parse Line
  42.       if (info.sline[1] = ';') then continue;
  43.  
  44.       split := SplitString(info.sline, ' ');
  45.       instruction := LowerCase(split[0]);
  46.      
  47.       if (Length(split) > 1) then
  48.         parameters := Copy(split, 1, Length(split)-1)
  49.       else
  50.         parameters := [''];
  51.      
  52.       // Assemble Instruction
  53.       try
  54.         case instruction of
  55.           'halt': begin
  56.             out := ConcatByteArrs(out, [OP_HALT]);
  57.           end;
  58.           'sys': begin
  59.             out := ConcatByteArrs(out, [OP_SYS]);
  60.           end;
  61.           'ld': begin
  62.             {
  63.               Possible Parameters
  64.               Param1
  65.                 Hardcoded Byte / Byte Const
  66.               Param2
  67.                 Hardcoded Any Type / Any Type Const
  68.                 Variable
  69.             }
  70.             tmp := ParseASMParam(parameters[0], [prmByte], FInterfaceData); // Causes Stack Overflow, why???
  71.             tmp := ConcatByteArrs(tmp, ParseASMParam(parameters[1], [prmAll], FInterfaceData));
  72.             out := ConcatByteArrs(out, ConcatByteArrs([OP_LD], tmp));
  73.           end;
  74.         else
  75.         begin
  76.           writeln('presdk-asm: ', info.path, ' (line ', IntToStr(info.cline), '): error: Invalid Instruction "', instruction, '"');
  77.         end;
  78.       end
  79.       except
  80.         on e: EInvalidParameterException do
  81.         begin
  82.           writeln('presdk-asm: ', info.path, ' (line ', IntToStr(info.cline), '): error: ',
  83.           e.Message);
  84.         end;
  85.       end;
  86.     end;
  87.  
  88.     result := out;
  89.   end;
  90.  
  91.   procedure TPREAssembler.Run(const AFile: String);
  92.   var
  93.     bytecode: TByteArray;
  94.     i: Integer;
  95.   begin
  96.     if not FileExists(AFile) then
  97.     begin
  98.       writeln('PREASM: error: File "', AFile, '" does not exist!');
  99.       exit;
  100.     end;
  101.  
  102.     info.path := AFile;
  103.     info.outpath := ExtractFilePath(AFile)+'/'+ExtractFileName(AFile)+'.prex';
  104.  
  105.     Assign(info._file, info.path);
  106.     ReSet(info._file);
  107.     info.sline := '';
  108.     info.cline := 0;
  109.  
  110.     // Interface Section
  111.     while not eof(info._file) and (info.sline <> '.start') do
  112.     begin
  113.       info.cline := info.cline + 1;
  114.       Readln(info._file, info.sline);
  115.     end;
  116.  
  117.     // Source Code
  118.     bytecode := Assemble;
  119.     for i := 0 to Length(bytecode)-1 do
  120.     begin
  121.       write(Format('%.2x ', [bytecode[i]]));
  122.       if (i mod 8 = 0) and (i > 0) then writeln;
  123.     end;
  124.     writeln;
  125.   end;
  126. end.
  127.  
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. unit uUtil;
  3.  
  4. interface
  5.   uses StrUtils, SysUtils, uASCII, uPRECodes;
  6.  
  7.   type
  8.     EInvalidParameterException = class(Exception);
  9.     EInvalidNamespaceException = class(Exception);
  10.     TParamTypes = set of (prmAll, prmBool, prmByte, prmShort, prmInt, prmLong, prmFloat, prmStr, prmVar);
  11.    
  12.     { Holds information on a Source-File, used for multisource }
  13.     TInterfaceData = record
  14.       name: String;
  15.       path: String;
  16.       procNames: TStringDynArray;
  17.       procIdents: TIntegerArray;
  18.       constNames: TStringDynArray;
  19.       constVals: TByteArrayArray;
  20.     end;
  21.     TInterfaceDataArr = array of TInterfaceData;
  22.  
  23.   { Converison Funcs }
  24.   function IntToBytes(const AInt: Integer): TByteArray;
  25.  
  26.   { Parsing Funcs }
  27.   function ParseASMParam(const AParam: String; const acceptableTypes: TParamTypes; var AInterfaceData: TInterfaceDataArr): TByteArray;
  28.  
  29.   { Other Funcs }
  30.   function ConcatByteArrs(AArr1: TByteArray; const AArr2: TByteArray): TByteArray;
  31.   function GetInterfaceData(const AArray: TInterfaceDataArr; const AName: String): TInterfaceData;
  32. implementation
  33.   function IntToBytes(const AInt: Integer): TByteArray;
  34.   begin
  35.     exit([
  36.           AInt and $FF00000000000000, AInt and $00FF000000000000, AInt and $0000FF0000000000,
  37.           AInt and $000000FF00000000, AInt and $00000000FF000000, AInt and $0000000000FF0000,
  38.           AInt and $000000000000FF00, AInt and $00000000000000FF
  39.         ]);
  40.   end;
  41.  
  42.   function ParseASMParam(const AParam: String; const acceptableTypes: TParamTypes; var AInterfaceData: TInterfaceDataArr): TByteArray;
  43.   var
  44.     prefix, value: String;
  45.     tmpInt: Integer;
  46.     cutcomma: Boolean;
  47.   begin
  48.     prefix := AParam[1];
  49.     value := Copy(AParam, 2, Length(AParam));
  50.     if EndsStr(',', value) then
  51.     begin
  52.       value := Copy(value, 1, Length(value)-1);
  53.       cutcomma := True;
  54.     end;
  55.  
  56.     if (prefix = '#') then
  57.     begin
  58.       if (value = 'true') or (value = 'false') then
  59.       begin
  60.         if prmBool in acceptableTypes then
  61.           if value = 'true' then exit([1]) else exit([0])
  62.         else
  63.           raise EInvalidParameterException.Create('Invalid Parameter Type!');
  64.       end;
  65.  
  66.       if ((Byte(value[1]) >= CHR_0) and (Byte(value[1]) <= CHR_9)) or (value[1] = '$') then // Number
  67.         exit(IntToBytes(StrToInt(value)))
  68.       else // Other Constant
  69.       begin
  70.         GetInterfaceData(AInterfaceData, 'test');
  71.         exit([$D0, $00]);
  72.       end;
  73.  
  74.       raise EInvalidParameterException.Create('Unrecognised Parameter Type! Parameter: '+value);
  75.     end;
  76.   end;
  77.  
  78.   function ConcatByteArrs(AArr1: TByteArray; const AArr2: TByteArray): TByteArray;
  79.   var
  80.     i: Integer;
  81.   begin
  82.     SetLength(AArr1, Length(AArr1) + Length(AArr2));
  83.     for i := 0 to Length(AArr2)-1 do
  84.       AArr1[i+Length(AArr2)] := AArr2[i];
  85.  
  86.     result := AArr1;
  87.   end;
  88.  
  89.   function GetInterfaceData(const AArray: TInterfaceDataArr; const AName: String): TInterfaceData;
  90.   var
  91.     intdat: TInterfaceData;
  92.   begin
  93.     for intdat in AArray do
  94.     begin
  95.       if (intdat.name = AName) then exit(intdat);
  96.     end;
  97.  
  98.     raise EInvalidNamespaceException.Create('Can''t find Interface-Data for Namespace: '+AName);
  99.   end;
  100. end.
  101.  
« Last Edit: November 17, 2022, 02:20:18 pm by Bertrahm »
i use arch btw

Thaddy

  • Hero Member
  • *****
  • Posts: 19273
  • Glad to be alive.
Re: Stack Overflow without decernable Reason
« Reply #1 on: November 16, 2022, 03:29:40 pm »
Use range checking and overflow checking to debug, you can also use stack thrashing. Also use line info. See compiler options.
« Last Edit: November 16, 2022, 03:31:34 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12430
  • Debugger - SynEdit - and more
    • wiki
Re: Stack Overflow without decernable Reason
« Reply #2 on: November 16, 2022, 03:39:57 pm »
What is your OS?

Do you compile with optimizations? -O2 or above? Does the error happen if you switch optimization off?

What does the debugger show?
=> For this make sure (if you don't already) you compile with debug info. And with range and stack checking (as Thaddy said).
=> Then open the stack window (View => debug windows) and get the content.

If you compile from commandline (i.e. if you do not use the Lazarus IDE) then run in whatever debugger you use (gdb/lldb) and get the stack from there.

MarkMLl

  • Hero Member
  • *****
  • Posts: 8572
Re: Stack Overflow without decernable Reason
« Reply #3 on: November 16, 2022, 03:44:48 pm »
Welcome to the forum. As others have hinted, you'd make things a bit easier if you showed your command line and precise results, since otherwise we don't know what range checking etc. is being applied.

One thing that does stand out is that a hex number like $ff00000000000000 will be interpreted as a signed literal (i.e. Int64) even though that's not your intention, you need to use qword($ff00000000000000) to get the correct bit pattern.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

jamie

  • Hero Member
  • *****
  • Posts: 7774
Re: Stack Overflow without decernable Reason
« Reply #4 on: November 16, 2022, 03:50:20 pm »
Please look at the definitions of TbyteArray, TIntegerArray etc.

Those types in my opinion were created to be used in a Casting or pointer situation.
 
 Maybe what you want to use is all dynamic instead?
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 #5 on: November 16, 2022, 03:52:20 pm »
What is your OS?

Do you compile with optimizations? -O2 or above? Does the error happen if you switch optimization off?

What does the debugger show?
=> For this make sure (if you don't already) you compile with debug info. And with range and stack checking (as Thaddy said).
=> Then open the stack window (View => debug windows) and get the content.

If you compile from commandline (i.e. if you do not use the Lazarus IDE) then run in whatever debugger you use (gdb/lldb) and get the stack from there.
Im on x86_64 Windows 11, the error also occurs when not compiling with optimizations. I have specified {$R+} and {$Q+} in the programs entry point.

Here is my compile command for debugging:
fpc src/PRESDK.pas -g -gt -Ct -Fu"../inc/" -FE"out/"

And here is the Stack info I can get from gdb:
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
  6.  called by frame at 0x142fde8
  7.  source language pascal.
  8.  Arglist at 0x142fa70, args: APARAM=..., ACCEPTABLETYPES=..., AINTERFACEDATA=0xc6e58955, result=0x0
  9.  Locals at 0x142fa70, Previous frame's sp is 0x142fa78
  10.  Saved registers:
  11.   ebp at 0x142fa70, edi at 0x142fa6c, eip at 0x142fa74

Edit: Meant to say that I specified {$R+} and {$Q+} within the main program unit, not inside the actual entry-point.
« Last Edit: November 16, 2022, 03:57:32 pm by Bertrahm »
i use arch btw

MMarie

  • New Member
  • *
  • Posts: 49
  • Right, lets bodge this pisspot
    • Homepage
Re: Stack Overflow without decernable Reason
« Reply #6 on: November 16, 2022, 03:54:57 pm »
Please look at the definitions of TbyteArray, TIntegerArray etc.

Those types in my opinion were created to be used in a Casting or pointer situation.
 
 Maybe what you want to use is all dynamic instead?

These type definitions come from another Unit within the project, which are dynamic.
i use arch btw

Zvoni

  • Hero Member
  • *****
  • Posts: 3399
Re: Stack Overflow without decernable Reason
« Reply #7 on: November 16, 2022, 03:59:22 pm »
Don't you have to set the Length of the Dynamic Array-Result before exiting?
Or is "Exit" doing it in the Background?

because that's the only thing i can see, that OP never sets the Length of the dynamic array, the resulting Byte-Array as well as that "var" Argument FInterface or whatever it's called
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

MMarie

  • New Member
  • *
  • Posts: 49
  • Right, lets bodge this pisspot
    • Homepage
Re: Stack Overflow without decernable Reason
« Reply #8 on: November 16, 2022, 04:03:11 pm »
Don't you have to set the Length of the Dynamic Array-Result before exiting?
Or is "Exit" doing it in the Background?

because that's the only thing i can see, that OP never sets the Length of the dynamic array, the resulting Byte-Array as well as that "var" Argument FInterface or whatever it's called

Atleast not in my experience, calling exit like e.g. exit([$00, $fe]); hasn't caused problems for me. I assume its set in the background
i use arch btw

jamie

  • Hero Member
  • *****
  • Posts: 7774
Re: Stack Overflow without decernable Reason
« Reply #9 on: November 16, 2022, 04:10:02 pm »
Please look at the definitions of TbyteArray, TIntegerArray etc.

Those types in my opinion were created to be used in a Casting or pointer situation.
 
 Maybe what you want to use is all dynamic instead?

These type definitions come from another Unit within the project, which are dynamic.

Please rest your mouse over those types in your code, all of your code to ensure that is true. These types also exist in the SysUtil unit too and order of units are important.
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 #10 on: November 16, 2022, 04:14:55 pm »
Please look at the definitions of TbyteArray, TIntegerArray etc.

Those types in my opinion were created to be used in a Casting or pointer situation.
 
 Maybe what you want to use is all dynamic instead?

These type definitions come from another Unit within the project, which are dynamic.

Please rest your mouse over those types in your code, all of your code to ensure that is true. These types also exist in the SysUtil unit too and order of units are important.

Since I'm not using an IDE I've just played "uPRECodes", which is the unit that  contains my definitions, nothing changes
i use arch btw

jamie

  • Hero Member
  • *****
  • Posts: 7774
Re: Stack Overflow without decernable Reason
« Reply #11 on: November 16, 2022, 04:26:32 pm »
I also noticed you are not using {$H+} strings, which means most likely all of your strings are shortstring which are 255 in length, without index sizing.
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 #12 on: November 16, 2022, 04:34:03 pm »
I just noticed that, very talently, misunderstood how exactly compiler flags like {$R+} work... Now with having properly added them, I get an ERangeError. Can't get any useful debug info anymore though, because the program immediatly exits on this error.
i use arch btw

Zvoni

  • Hero Member
  • *****
  • Posts: 3399
Re: Stack Overflow without decernable Reason
« Reply #13 on: November 16, 2022, 05:35:00 pm »
No IDE?
Then writeln each value at each step. So you can see what‘s the real cause of the exception
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

MMarie

  • New Member
  • *
  • Posts: 49
  • Right, lets bodge this pisspot
    • Homepage
Re: Stack Overflow without decernable Reason
« Reply #14 on: November 16, 2022, 06:13:17 pm »
No IDE?
Then writeln each value at each step. So you can see what‘s the real cause of the exception

The values are all OK, the Error definetly comes from the method call unless i'm missing something
i use arch btw

 

TinyPortal © 2005-2018