Recent

Author Topic: reading from out of array bounds  (Read 1974 times)

inky

  • New Member
  • *
  • Posts: 41
    • github
reading from out of array bounds
« on: April 21, 2021, 02:47:55 pm »
i think i remember that this kind of code was not possible to compile:

Code: [Select]
var
  a : array [0..5] of integer;

begin
   writeln(a[15]);
end.

did something change or broke? or do i remember incorrectly?
then why is this legal?

Zvoni

  • Hero Member
  • *****
  • Posts: 2327
Re: reading from out of array bounds
« Reply #1 on: April 21, 2021, 03:14:11 pm »
?
https://www.freepascal.org/docs-html/prog/progsu65.html
Quote
By default, the compiler doesn’t generate code to check the ranges of array indices, enumeration types, subrange types, etc.
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

wp

  • Hero Member
  • *****
  • Posts: 11906
Re: reading from out of array bounds
« Reply #2 on: April 21, 2021, 03:55:18 pm »
did something change or broke?
In the default installation of Lazarus the compilation checks (range check, overflow, etc) are off. Therefore your code passes compilation (although a warning is given "project1.lpr(6,14) Warning: Range check error while evaluating constants (15 must be between 0 and 5)". However, when you turn Range Checking on ("Project Options" > "Compiler options" > "Debugging"), the code is no langer accepted.

inky

  • New Member
  • *
  • Posts: 41
    • github
Re: reading from out of array bounds
« Reply #3 on: April 22, 2021, 01:29:57 pm »
thank you!

i was expecting that there should be a runtime check and compile time check.

and i was thinking that the compile time check is necessary because of the language standard. but i understand now that it's not even clear if there is such a language standard, because these delphi/objfpc dialects are not standardized.

and now we have to rely on compiler and compiler checks. i am surprised that the compiler is not "obliged" to interrupt the compilation, but that depends on the switch.

so practically we have the implementation that defines the standard, not vice versa.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5462
  • Compiler Developer
Re: reading from out of array bounds
« Reply #4 on: April 22, 2021, 01:34:24 pm »
and now we have to rely on compiler and compiler checks. i am surprised that the compiler is not "obliged" to interrupt the compilation, but that depends on the switch.

The default is off, because there is legitimate code that uses this behaviour, especially when interfacing with code like the Windows API:

Code: Pascal  [Select][+][-]
  1.    tagSAFEARRAY = record
  2.      cDims: USHORT;
  3.      fFeatures: USHORT;
  4.      cbElements: ULONG;
  5.      cLocks: ULONG;
  6.      pvData: PVOID;
  7.      rgsabound: array[0..0] of SAFEARRAYBOUND;
  8.    end;
  9.    TSafeArray = tagSAFEARRAY;
  10.    SAFEARRAY = TSafeArray;
  11.  

This is from the ActiveX unit. With bounds checks enabled one wouldn't be able to access all elements of rgsabound.

Handoko

  • Hero Member
  • *****
  • Posts: 5149
  • My goal: build my own game engine using Lazarus
Re: reading from out of array bounds
« Reply #5 on: April 22, 2021, 01:50:02 pm »
I prefer it off by default. Because it has significant impact on performance on certain types of programs, for example games.
« Last Edit: April 22, 2021, 01:51:34 pm by Handoko »

440bx

  • Hero Member
  • *****
  • Posts: 4014
Re: reading from out of array bounds
« Reply #6 on: April 22, 2021, 02:25:12 pm »
The default is off, because there is legitimate code that uses this behaviour,
That range checking is off by default is fine.  What is NOT fine is that when a constant that is out of bounds is used, the compiler should NOT accept that because it knows it is not just a bounds violation, it is also a data type violation.

Of course, it's a different story when using variables, because obviously the compiler cannot know if a variable is out of bounds at compile time, which is implicit in the example you provided but, that example doesn't apply at compile time because it uses variables instead of constants.

especially when interfacing with code like the Windows API:

Code: Pascal  [Select][+][-]
  1.    tagSAFEARRAY = record
  2.      cDims: USHORT;
  3.      fFeatures: USHORT;
  4.      cbElements: ULONG;
  5.      cLocks: ULONG;
  6.      pvData: PVOID;
  7.      rgsabound: array[0..0] of SAFEARRAYBOUND;
  8.    end;
  9.    TSafeArray = tagSAFEARRAY;
  10.    SAFEARRAY = TSafeArray;
  11.  

This is from the ActiveX unit. With bounds checks enabled one wouldn't be able to access all elements of rgsabound.

Anyway, I know this is not going to change (unfortunately) but, for the OP, a _correctly_ implemented Pascal compiler would NOT accept a constant index out of the array bounds and, as an example, Delphi refuses it (as it should.)
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 14357
  • Sensorship about opinions does not belong here.
Re: reading from out of array bounds
« Reply #7 on: April 22, 2021, 02:35:37 pm »
Delphi refuses it (as it should.)
Not correct. At least D7 and XE2 [edit: same with D10.1] accept it (The array[0..0] construct). But a warning is given. Delphi uses similar constructs like PascalDragon described.
Furthermore you can not simply state that Delphi accepts it without referring to a version. That is the same in FreePascal: explanation follows from version. Leaving the version out leads to noice.

If possible, use a custom range. In that case both FPC and Delphi catch the error at compile time given a compile time const.

(Note that the real issue is that you can cause stack problems)
« Last Edit: April 22, 2021, 02:40:34 pm by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

440bx

  • Hero Member
  • *****
  • Posts: 4014
Re: reading from out of array bounds
« Reply #8 on: April 22, 2021, 03:09:57 pm »
Not correct. At least D7 and XE2 [edit: same with D10.1] accept it (The array[0..0] construct). But a warning is given. Delphi uses similar constructs like PascalDragon described.
Furthermore you can not simply state that Delphi accepts it without referring to a version. That is the same in FreePascal: explanation follows from version. Leaving the version out leads to noice.

If possible, use a custom range. In that case both FPC and Delphi catch the error at compile time given a compile time const.

(Note that the real issue is that you can cause stack problems)
Sometimes I think you post nonsense just to start an argument even though you know beforehand you are wrong.

The OP showed this code :
Code: Pascal  [Select][+][-]
  1. var
  2.   a : array [0..5] of integer;
  3.  
  4. begin
  5.    writeln(a[15]);
  6. end.
and Delphi will NOT compile that. 

There is one thing you are correct in, I have not tested it in every version of Delphi (nor do I intend to) but, I very strongly doubt that any version would compile that _incorrect_ program that FPC _incorrectly_ accepts.

As I stated in the previous post, when using _constants_ and, FYI, in a[15] the numeral 15 is a _constant_ and it is out of the array bounds, the compiler should summarily reject it.  No correctly implemented Pascal compiler would accept that and, the reason is because the out of bounds constant represents a _data type_ violation.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

pascal111

  • Sr. Member
  • ****
  • Posts: 423
  • Un trabajo en equipo para programas serias.
Re: reading from out of array bounds
« Reply #9 on: May 03, 2021, 11:19:17 pm »
Can this checking help:
(untested)

Code: Pascal  [Select][+][-]
  1.     var
  2.       a : array [0..5] of integer;
  3.       x:integer;
  4.     begin
  5.        
  6.        x=15;      
  7.  
  8.        if (x>=low(a)) and (x<=high(a)) then
  9.        writeln(a[x]);
  10.  
  11.     end.
  12.  
La chose par la chose est rappelé.

 

TinyPortal © 2005-2018