5

I've been looking through this Ada 95 tutorial. I was reading that it is possible to define a type that has a range that is different than the standard range, and if the program tries to go outside this range it will throw an error. While working on my own program I noticed that if the end of the range in the definition falls on the boundary for of its underlying type then the program will not raise the CONSTRAINT_ERROR when assigning values out of that range. Instead it will happily keep going and then wrap around. I wrote a program to explicitly show this.

Does anyone know of an Ada rule that explains this behavior?

-Kirk

Here is the output from my terminal, the source code is below that.

me@acheron:~/Dropbox/programs/ada$ gnatmake constraints.adb -f
gcc-4.6 -c constraints.adb
gnatbind -x constraints.ali
gnatlink constraints.ali
me@acheron:~/Dropbox/programs/ada$ ./constraints

Type ON has size:           7
It has a min/max of:           0        127
It's base has a min/max of:        -128        127

Type UNDER has size:           7
It has a min/max of:           0        126
It's base has a min/max of:        -128        127
The value of No_Error is:         245

raised CONSTRAINT_ERROR : constraints.adb:58 range check failed
me@acheron:~/Dropbox/programs/ada$

Source Code:

with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;

Procedure Constraints is

    type UNDER is range 0..126;
    type ON is range 0..127;
    type OVER is range 0..128;    

    Error : UNDER := 0;
    No_Error : ON := 0;

    Index : INTEGER := 0;

begin
    New_Line;
    Put("Type ON has size: ");
    Put(INTEGER(ON'SIZE));
    New_Line;
    Put("It has a min/max of: ");
    Put(INTEGER(ON'FIRST));
    Put(INTEGER(ON'LAST));
    New_Line;
    Put("It's base has a min/max of: ");
    Put(INTEGER(ON'BASE'FIRST));
    Put(INTEGER(ON'BASE'LAST));

    New_Line;
    New_Line;

    Put("Type UNDER has size: ");
    Put(INTEGER(UNDER'SIZE));
    New_Line;
    Put("It has a min/max of: ");
    Put(INTEGER(UNDER'FIRST));
    Put(INTEGER(UNDER'LAST));
    New_Line;
    Put("It's base has a min/max of: ");
    Put(INTEGER(UNDER'BASE'FIRST));
    Put(INTEGER(UNDER'BASE'LAST));

    Safe_Loop:
    loop
        No_Error := No_Error + 1;
        Index := Index + 1;
        --Put(INTEGER(No_Error));
        exit Safe_Loop when Index = 245;  
    end loop Safe_Loop;

    New_Line;
    Put("The value of No_Error is: ");
    Put(INTEGER(No_Error));

    Index := 0;

    Crash_Loop:
    loop
        Error := Error + 1;
        Index := Index + 1;
        exit Crash_Loop when Index = 245;
    end loop Crash_Loop;


end Constraints;
chew socks
  • 1,406
  • 2
  • 17
  • 37

1 Answers1

3

According to the documentation:

Note again that -gnato is off by default, so overflow checking is not performed in default mode. This means that out of the box, with the default settings, GNAT does not do all the checks expected from the language description in the Ada Reference Manual. If you want all constraint checks to be performed, as described in this Manual, then you must explicitly use the -gnato switch either on the gnatmake or gcc command.

That said, the documentation also claims that:

Basically the rule is that in the default mode (-gnato not used), the generated code assures that all integer variables stay within their declared ranges, or within the base range if there is no declared range. This prevents any serious problems like indexes out of range for array operations. ¶ What is not checked in default mode is an overflow that results in an in-range, but incorrect value.

which seems to be wrong in the case you describe, since No_Error really does end up completely outside its range. So this seems to go beyond "not […] expected from the language description" and into the realm of "compiler bug"; but at least you should be able to fix it by adding the -gnato flag.

ruakh
  • 175,680
  • 26
  • 273
  • 307
  • Thank you for that information. I tried recompiling with -gnato and then running. The result was "raised CONSTRAINT_ERROR : constraints.adb:44 overflow check failed" which is still different than the "range check failed" error that is raised from overfilling the variable Error. – chew socks Oct 10 '12 at 03:27
  • Why is it that it doesn't fail with a "range check error" since it is outside of the declared range? – chew socks Oct 10 '12 at 03:35
  • @chewsocks: Well, because of the bug that you saw. When I said "that makes sense", I didn't mean that the compiler is behaving correctly, only that the one behavior made sense in light of the other. – ruakh Oct 10 '12 at 04:12
  • Oh I understand now. I suppose I should file a bug report with GCC then. – chew socks Oct 10 '12 at 04:44
  • The fact that this is off by default on Gnat really annoys us Ada purists, but I'm sure it helps Ada Core's benchmark numbers. :-( – T.E.D. Oct 10 '12 at 19:00
  • Are there any other switches that default to off that purists would prefer be on? – chew socks Oct 11 '12 at 01:17
  • Does anyone have a suggestion as to what severity this should be in the bug report? I was thinking that on one hand it is important since it violates the Reference Manual, but on the other hand compiling with "-gnato" is a work around. – chew socks Oct 11 '12 at 04:32
  • definitely -gnatE and prolly -fstack-check – darkestkhan Oct 11 '12 at 05:02