Recent

Author Topic: [Solved] Unexpected ERangeError:Range check error  (Read 4251 times)

Wilko500

  • Full Member
  • ***
  • Posts: 180
[Solved] Unexpected ERangeError:Range check error
« on: November 15, 2024, 11:43:46 pm »
I have just started my first foray into serial comms using LazSerial/SynaSer.  I anticipate that there may well be questions on that later. For now though I need to compute a checksum for a returned Byte array and have created a function to achieve that.  It works as expected, or at least it did until I changed from release mode to debug mode (including the range check option) when I started getting range check error that I was not expecting because the function was working. I suspect my lack of experience caused me to incorrectly(?) search for a coding error that is not there. Variables tmp and new are both of type Byte
Code: Pascal  [Select][+][-]
  1.       tmp:=new << 4;        //<< ERangeError:Range check error

I have solved the problem by the addition of compiler directives to turn off range checks for this function. However I would like to understand why this range check error is reported.  Perhaps someone can enlighten me.
Code: Pascal  [Select][+][-]
  1. Function TestChkSum(b:Array Of Byte): Int32;
  2. Var
  3.   i:               Int32;   //Loop counter
  4.   l:               Int32;   //Length of supplied byte array
  5.   BccLow, BccHigh: Byte;    //Low ond high checksum bytes
  6.   tmp, new:        Byte;    //Work vars for checksum calculation
  7.   Res:             Int32;   //Holder for function result code
  8. Begin
  9. Try
  10. {$RangeChecks OFF}
  11.   Res:=0;  //assume good checksum
  12.   BccLow:=$ff;
  13.   BccHigh:=$ff;
  14.   l:=Length(b);
  15.   For i:= 0 to l-3 Do     //byte aray zero based and not checking last 2 bytes
  16.       Begin
  17.       new:=b[i];
  18.       new:=new xor BccLow;
  19.       tmp:=new << 4;        //<< ERangeError:Range check error
  20.       new:=tmp xor new;
  21.       tmp:=new >> 5;
  22.       BccLow:=BccHigh;
  23.       BccHigh:=new xor tmp;
  24.       tmp:=new << 3;        //<< ERangeError:Range check error
  25.       BccLow:=BccLow xor tmp;
  26.       tmp:= new >> 4;
  27.       BccLow:=BccLow xor tmp;
  28.   End;{For}
  29.   BccLow:=Not BccLow;
  30.   BccHigh:=Not BccHigh;
  31.   //Test if provided checksum matches computed value
  32.   If (b[6] <> BccLow) Or (b[7] <> BccHigh) Then
  33.       //No, checksum test failed
  34.       Begin
  35.       Res:=1
  36.   End;{If}
  37.   Result:=Res;
  38. {$RangeChecks ON}
  39. Except
  40.   On E: Exception Do
  41.   Begin
  42.   WriteLn('Exception in TestChkSum: ' + E.ClassName + ':' + E.Message);
  43.   Result:=1;
  44.   End;
  45. End;{Try}
  46. End;{Function TestChkSum}
« Last Edit: November 16, 2024, 12:24:55 am by Wilko500 »
MacBook Pro mid 2015 with OS Monterey 12.7.6
FPC 3.2.3 Lazarus 3.7
FPC 3.2.2 Lazarus 3.4

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: Unexpected ERangeError:Range check error
« Reply #1 on: November 15, 2024, 11:54:12 pm »
If you shift bits (out) of a certain type tyhen the answer will not fit into the same type anymore.

Cast the answer of your shifts to a byte (or and it off) and you should be good to go.
Today is tomorrow's yesterday.

jamie

  • Hero Member
  • *****
  • Posts: 7587
Re: Unexpected ERangeError:Range check error
« Reply #2 on: November 16, 2024, 12:07:54 am »
Must be some broken compilers out there recently? I've been seeing this sort of issue with the recent release of Lazarus, but I am still at Lazarus 3.4, and I just tested that code and works just fine here with Lazarus 3.4-Fpc 3.2.2

If you wrap the expression with a Byte, that should also work but really, turning off the Range check in mid-stream should also work. It works here, but obviously not there. I am on Windows.

The only true wisdom is knowing you know nothing

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: Unexpected ERangeError:Range check error
« Reply #3 on: November 16, 2024, 12:14:24 am »
No idea what you are talking about jamie.

Code: Pascal  [Select][+][-]
  1.   writeln(sizeof($f shl 1));
  2.   writeln(sizeof($ff shl 1));
  3.   writeln(sizeof($ffff shl 1));
  4.   writeln(sizeof($ffffffff shl 1));
  5.  

Code: [Select]
1
2
4
8
Today is tomorrow's yesterday.

Wilko500

  • Full Member
  • ***
  • Posts: 180
Re: Unexpected ERangeError:Range check error
« Reply #4 on: November 16, 2024, 12:16:25 am »
If you shift bits (out) of a certain type then the answer will not fit into the same type anymore.
Ah!  I realise that but I always thought that the shifted bits were ignored if they shifted out of the byte being shifted.  This is presumably what happens with shift right which does not error.
This worked. Thank you.
Code: Pascal  [Select][+][-]
  1.       tmp:=(new << 4) AND $FF;
MacBook Pro mid 2015 with OS Monterey 12.7.6
FPC 3.2.3 Lazarus 3.7
FPC 3.2.2 Lazarus 3.4

Wilko500

  • Full Member
  • ***
  • Posts: 180
Re: Unexpected ERangeError:Range check error
« Reply #5 on: November 16, 2024, 12:24:40 am »
Just for the record I'm using FPC 3.2.3 Lazarus 3.5 (on MacOs) at the moment installed by fpcupdeluxe fixes.
MacBook Pro mid 2015 with OS Monterey 12.7.6
FPC 3.2.3 Lazarus 3.7
FPC 3.2.2 Lazarus 3.4

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: Unexpected ERangeError:Range check error
« Reply #6 on: November 16, 2024, 12:24:52 am »
Ah!  I realise that but I always thought that the shifted bits were ignored if they shifted out of the byte being shifted.  This is presumably what happens with shift right which does not error.
Indeed. It requires a bit of thought. I always think of it as shift left is multiply (number becomes bigger) and shift right is divide (number becomes smaller).

The latter will still fit though perhaps in a smaller type (in your case there isn't anything smaller than a byte) while the former /might/ not fit into the same type anymore (it depends on what bits where set in the byte and how many times those bits where shifted).

When doing shifts or checksum related work always make sure to cast (or what you did and off) the result so that it will still fit into the destination type.
Today is tomorrow's yesterday.

jamie

  • Hero Member
  • *****
  • Posts: 7587
Re: Unexpected ERangeError:Range check error
« Reply #7 on: November 16, 2024, 12:25:57 am »
Looks like hack to me

Code: Pascal  [Select][+][-]
  1. ByteResults := Byte(New << 4);
  2.  
  3.  

The compiler always tries to elevate the expression to an integer.

 You know, the Delphi compiler handles this correctly, you don't know this crap.



The only true wisdom is knowing you know nothing

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: Unexpected ERangeError:Range check error
« Reply #8 on: November 16, 2024, 12:30:38 am »
You know, the Delphi compiler handles this correctly, you don't know this crap.
Thank you very much for that confirmation. I wasn't sure.

* TRon throws some carry flags around
Today is tomorrow's yesterday.

Wilko500

  • Full Member
  • ***
  • Posts: 180
Re: [Solved] Unexpected ERangeError:Range check error
« Reply #9 on: November 16, 2024, 12:37:31 am »
When doing shifts or checksum related work always make sure to cast (or what you did and off) the result so that it will still fit into the destination type.
This function to calculate checksum was my first use of both checksums and shifting. So today I learned something new.  Should serve me well in my current project which will have lots of manipulating and decoding byte arrays.  I am attempting to create a MacOS version of Aurora Communicator (only available on Windows) to offload solar data from my inverter via RS485 serial coms.
MacBook Pro mid 2015 with OS Monterey 12.7.6
FPC 3.2.3 Lazarus 3.7
FPC 3.2.2 Lazarus 3.4

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: [Solved] Unexpected ERangeError:Range check error
« Reply #10 on: November 16, 2024, 01:02:23 am »
@Wilko500
I do hope it serves you well indeed (for sure sound like it and seem like an interesting project going on there).

You know that some don't even bother with checks and just publish their code that way ? Because why should someone bother when you can turned off the checks for certain parts of your code (that are known to be wrong).
Today is tomorrow's yesterday.

PascalDragon

  • Hero Member
  • *****
  • Posts: 6349
  • Compiler Developer
Re: Unexpected ERangeError:Range check error
« Reply #11 on: November 16, 2024, 02:23:36 pm »
You know, the Delphi compiler handles this correctly, you don't know this crap.

Did you even try with range checks enabled? I just tested with Delphi 10.2:

Code: Pascal  [Select][+][-]
  1. program trangechk;
  2.  
  3. {$R+}
  4.  
  5. uses
  6.   SysUtils;
  7.  
  8. var
  9.   b1, b2: Byte;
  10. begin
  11.   b1 := $FF;
  12.   try
  13.     b2 := b1 shl 4;
  14.   except
  15.     on e: Exception do
  16.       Writeln(e.ClassName, ': ', e.Message);
  17.   end;
  18.   b2 := Byte(b1 shl 4);
  19.   Writeln(IntToHex(b2, 2));
  20. end.

Output:

Code: [Select]
ERangeError: Fehler bei Bereichsprüfung
F0

The main point is that (Object) Pascal does not determine the result of an expression based on the left side of an assignment (with only two exceptions for this: assignment of overloaded functions to function pointers and determining which assignment operator is called). This is true for both FPC and Delphi.

Note: with range checks disabled this will also run without error in FPC.
« Last Edit: November 16, 2024, 02:26:41 pm by PascalDragon »

 

TinyPortal © 2005-2018