Recent

Author Topic: static array [0..0] now fail at run time  (Read 3323 times)

rossh_lz

  • New Member
  • *
  • Posts: 21
static array [0..0] now fail at run time
« on: November 21, 2020, 01:56:56 pm »
The old method of defining a static type of array with an open ended size, now fails a runtime. 

sample:
  PCells = array [0..3] of Byte;
  TPArray = array [0..0] of PCells;
  PTPArray = ^TPArray;

The TPArray array can be sized to suit with GetMem, or assigning existing mem to PTPArray.


Now, as of FPC 3.2.0, I get range check fatal error on every attempt to access an array index > 0.  Code that still runs OK in Delphi, and for the last 12 years in Lazarus, now fails.

Range checking is not active (and never affected this anyway).

Why the implied range checking now here?  How to get rid of it?

Thanks.
« Last Edit: November 21, 2020, 02:01:05 pm by rossh_lz »

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 1058
Re: static array [0..0] now fail at run time
« Reply #1 on: November 21, 2020, 02:15:42 pm »
The range check at compile time was added because it has always generated code that gave unexpected results in some cases (even when range checking was inactive). You can find a very long thread about this at https://forum.lazarus.freepascal.org/index.php/topic,44655.0.html . It seemed more prudent to give a compile time error than to silently generate unexpected code.

Since both FPC and Delphi support indexing pointers as arrays, the portable and safe way to implement what you want is to declare PTPArray as ^PCells instead. If you're using {$mode delphi}, and for Delphi proper, you also need to enable the pointermath switch. You should not need to make any other changes to your code.
« Last Edit: November 21, 2020, 02:19:49 pm by Jonas Maebe »

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: static array [0..0] now fail at run time
« Reply #2 on: November 21, 2020, 02:21:13 pm »
The old method of defining a static type of array with an open ended size, now fails a runtime. 

You are comparing with Delphi, I assume you have enabled delphi mode?

nanobit

  • Full Member
  • ***
  • Posts: 160
Re: static array [0..0] now fail at run time
« Reply #3 on: November 21, 2020, 02:22:25 pm »
sample:
  PCells = array [0..3] of Byte;
  TPArray = array [0..0] of PCells;
  PTPArray = ^TPArray;

You can define a larger range:
type TPArray = array[0..(high(sizeint) div sizeof(PCells))-1] of PCells;

if you need also negative indices, then you need pointermath instead.
type {$PointerMath on} PTPArray = ^PCells; {$PointerMath off}
But FPC has a known bug here (if item is static array, issue 35745) under {$modeswitch autoderef} and delphi mode:

Then "var pArrays: PTPArray;" has this pointermath bug:
pArrays[1] is next byte, but should be next array (PCells).
( pArrays^[1] (non-pointermath expression) is correct for returning a byte)
Workaround: (pArrays + 1)^ is next array.

@pArrays[1] refers to next byte, but should refer to next array.
Workaround: (pArrays + 1) refers to next array.
« Last Edit: November 21, 2020, 07:14:41 pm by nanobit »

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: static array [0..0] now fail at run time
« Reply #4 on: November 21, 2020, 06:18:09 pm »
Now, as of FPC 3.2.0, I get range check fatal error on every attempt to access an array index > 0.  Code that still runs OK in Delphi, and for the last 12 years in Lazarus, now fails.

This code fails to compile in current Delphi versions as well (also with range checks disabled):

Code: Pascal  [Select][+][-]
  1. type
  2.   PCells = array [0..3] of Byte;
  3.   TPArray = array [0..0] of PCells;
  4.   PTPArray = ^TPArray;
  5.  
  6. var
  7.   p: PTPArray;
  8. begin
  9.   GetMem(p, 10 * SizeOf(PCells));
  10.   Writeln(p^[2]^);
  11. end.

The error generated is E1012: constant expression violates subrange bounds.

@Jonas: maybe this should be mentioned in User Changes 3.2.0?

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: static array [0..0] now fail at run time
« Reply #5 on: November 21, 2020, 06:46:54 pm »
The error generated is E1012: constant expression violates subrange bounds.
Does it generate correct code in 64bit mode when the index is a 32bit integer _variable_ less than zero ?
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

rossh_lz

  • New Member
  • *
  • Posts: 21
Re: static array [0..0] now fail at run time
« Reply #6 on: November 21, 2020, 07:56:37 pm »
Now, as of FPC 3.2.0, I get range check fatal error on every attempt to access an array index > 0.  Code that still runs OK in Delphi, and for the last 12 years in Lazarus, now fails.

This code fails to compile in current Delphi versions as well (also with range checks disabled):

Code: Pascal  [Select][+][-]
  1. type
  2.   PCells = array [0..3] of Byte;
  3.   TPArray = array [0..0] of PCells;
  4.   PTPArray = ^TPArray;
  5.  
  6. var
  7.   p: PTPArray;
  8. begin
  9.   GetMem(p, 10 * SizeOf(PCells));
  10.   Writeln(p^[2]^);
  11. end.

The error generated is E1012: constant expression violates subrange bounds.

@Jonas: maybe this should be mentioned in User Changes 3.2.0?

Yes, your sample above fails, because the hard coded index of 2, is beyond range at compile time.

But this code below works and it's the beauty of using static 0..0 arrays.  This was a way to get dynamic arrays, before real dynamic array were available.

Code: Pascal  [Select][+][-]
  1.     var
  2.       i, j: Integer;
  3.       p: PTPArray;
  4.     begin
  5.       GetMem(p, 10 * SizeOf(PCells));
  6.       i := 7;
  7.       j := 1;
  8.       p^[i][j] := 4;
  9.       for i := 1 to 9 do
  10.         p^[i] := p^[i-1];
  11.     end;

The issue is, the above works just fine in Delphi, and all previous FPC, except the latest 3.2.0, where it seems that runtime range checking of static arrays has been added.  This is not mentioned in the notes (and not welcome either).
« Last Edit: November 21, 2020, 08:07:20 pm by rossh_lz »

nanobit

  • Full Member
  • ***
  • Posts: 160
Re: static array [0..0] now fail at run time
« Reply #7 on: November 21, 2020, 08:11:38 pm »
But this code below works and it's the beauty of using static 0..0 arrays. 

array [0..0] means single element,
this is less than beautiful for larger arrays.

jamie

  • Hero Member
  • *****
  • Posts: 6091
Re: static array [0..0] now fail at run time
« Reply #8 on: November 21, 2020, 08:29:21 pm »
the easy fix which I am sure will work in all versions is this.

Code: Pascal  [Select][+][-]
  1. Type
  2.   PCells = array [0..3] of Byte;
  3.   PTPArray = ^PCells;  
  4.  ///---- Code land ---//
  5. Var
  6.   p:PTpArray;
  7. begin
  8.   getmem(p, sizeof(Pcells)*10);
  9.   P[5][0] := 10;
  10. end;                    
  11.              
  12.  

ect.
The only true wisdom is knowing you know nothing

rossh_lz

  • New Member
  • *
  • Posts: 21
Re: static array [0..0] now fail at run time
« Reply #9 on: November 21, 2020, 08:32:00 pm »
But this code below works and it's the beauty of using static 0..0 arrays. 

array [0..0] means single element,
this is less than beautiful for larger arrays.

No.   The beauty is that it's open ended for size, and the use of indexes at runtime, mean you are not constrained to declaring array sizes at design time.   This was how you had to do it before dynamic arrays were available.

nanobit

  • Full Member
  • ***
  • Posts: 160
Re: static array [0..0] now fail at run time
« Reply #10 on: November 21, 2020, 08:36:30 pm »
the easy fix which I am sure will work in all versions is this.

Code: Pascal  [Select][+][-]
  1. Type
  2.   PCells = array [0..3] of Byte;
  3.   PTPArray = ^PCells;  
  4.  

Not all versions. As stated earlier, works only with {$PointerMath on},
and if none of the following is true: {$modeswitch autoderef}, {$mode delphi}

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: static array [0..0] now fail at run time
« Reply #11 on: November 21, 2020, 08:43:32 pm »
The error generated is E1012: constant expression violates subrange bounds.
Does it generate correct code in 64bit mode when the index is a 32bit integer _variable_ less than zero ?

I don't have a 64-bit Delphi.

The issue is, the above works just fine in Delphi, and all previous FPC, except the latest 3.2.0, where it seems that runtime range checking of static arrays has been added.  This is not mentioned in the notes (and not welcome either).

As long as I don't enable range checking the following code compiles and runs without problems on FPC 3.2.0 and newer (and if I enable $R there'll be a runtime error in both FPC and Delphi):

Code: Pascal  [Select][+][-]
  1. program tarrtest;
  2.  
  3. {$mode objfpc}
  4.  
  5. type
  6.   PCells = array [0..3] of Byte;
  7.   TPArray = array [0..0] of PCells;
  8.   PTPArray = ^TPArray;
  9.  
  10. var
  11.  i, j: Integer;
  12.  p: PTPArray;
  13. begin
  14.  GetMem(p, 10 * SizeOf(PCells));
  15.  i := 7;
  16.  j := 1;
  17.  p^[i][j] := 4;
  18.  for i := 1 to 9 do
  19.    p^[i] := p^[i-1];
  20. end.

So please provide a full example including compiler parameters that fails for you that you think shouldn't fail.

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: static array [0..0] now fail at run time
« Reply #12 on: November 21, 2020, 08:48:05 pm »
The error generated is E1012: constant expression violates subrange bounds.
Does it generate correct code in 64bit mode when the index is a 32bit integer _variable_ less than zero ?

I don't have a 64-bit Delphi.
I wasn't asking about Delphi.  It works in Delphi.  I was asking if FPC 3.2.0 generates correct code when in 64bit mode with an index that is a 32bit integer variable with a value less than zero.  (FPC 3.0.4 does not because it fails to sign extend the 32bit integer variable.)
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: static array [0..0] now fail at run time
« Reply #13 on: November 21, 2020, 09:07:59 pm »
The error generated is E1012: constant expression violates subrange bounds.
Does it generate correct code in 64bit mode when the index is a 32bit integer _variable_ less than zero ?

I don't have a 64-bit Delphi.
I wasn't asking about Delphi.  It works in Delphi.  I was asking if FPC 3.2.0 generates correct code when in 64bit mode with an index that is a 32bit integer variable with a value less than zero.  (FPC 3.0.4 does not because it fails to sign extend the 32bit integer variable.)

Nothing was changed in this regard compared to the previous thread that was already linked here.

nanobit

  • Full Member
  • ***
  • Posts: 160
Re: static array [0..0] now fail at run time
« Reply #14 on: November 22, 2020, 08:57:11 am »
array [0..0] means single element, this is less than beautiful for larger arrays.

No. The beauty is that it's open ended for size, and the use of indexes at runtime, mean you are not constrained to declaring array sizes at design time.   This was how you had to do it before dynamic arrays were available.

Truly open-ended (unchecked) is only pointermath (see previous comments).
array[0..max] is open-ended with maximum, which is range-checked {$R}.
Open-ended because you use PTPArray only with dynamic array-size, but not: var a: TPArray; sizeof(TPArray); high(TPArray).
array[0..0] is just one example of non-empty ranges.
 
(max+1)*sizeOf(element) must lie within the maximum dynamic allocation size of your array
(constrained by memory manager or api function if you don't know a lower maximum).
Index (0 or larger) can still point to invalid dynamic memory, regardless of range declaration.
If your variables use only type PTPArray, you can change your example to:
type TPArray = array[0..(high(sizeint) div sizeof(PCells))-1] of PCells;
type PTPArray = ^TPArray; var p: PTPArray;
« Last Edit: November 22, 2020, 10:42:03 am by nanobit »

 

TinyPortal © 2005-2018