3

We recently updated GCC versions (4.8.2 to 5.3.0) and started receiving unexpected constraint errors in some Ada applications. I've reduced it to the following:

-- moo.adb
with text_io;
procedure moo is
   type thing_type is (something1,something2,something3,something4,something5,something6);
   for thing_type use (something1 => 1,something2 => 2,something3 => 
      3,something4 => 4,something5 => 5,something6 => 6);
   for thing_type'size use 32;
   type thing_array_t is array (0 .. 5) of thing_type;
   thing_array : thing_array_t := (others => something1);
begin
   text_io.put_line("item 0 = " & thing_type'image(thing_array(0)));
end moo;

This program will compile just fine on either GCC version (simply compiled with "gnatmake moo.adb".) When built with 4.8.2, the output is as expected:

item 0 = SOMETHING1

When built with 5.0.3, we instead receive

raised CONSTRAINT_ERROR : moo.adb:13 invalid data

Interestingly, the results are exactly the same when compiled as 32 and 64 bit. Many things can be changed to make the program work fine with 5.3.0: removing the thing_type'size clause, adding or removing values to the enumerator, changing the number of items in the array, using a different value for initializing the array, etc. Are there any obvious problems with this code that could account for this behavior?

Kevin
  • 510
  • 4
  • 16

2 Answers2

6

This bug is still present in GCC 7.0.1. Running under the debugger, output slightly edited,

(gdb) catch exception
Catchpoint 2: all Ada exceptions
(gdb) run
Starting program: /Users/simon/tmp/so/moo 
[New Thread 0x1703 of process 75511]

Catchpoint 2, CONSTRAINT_ERROR (moo.adb:10 invalid data) at 0x0000000100001abe in _ada_moo () at moo.adb:10
10     text_io.put_line("item 0 = " & thing_type'image(thing_array(0)));
(gdb) p thing_array
$5 = (0 => 16843009, 16843009, 16843009, 16843009, 16843009, 16843009)
(gdb) p/x thing_array
$6 = (0 => 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101)

so GNAT has mistakenly set each byte of thing_array elements to 16#01#, rather than the whole element.

The same happens if something1 is set to 2 (and later values incremented, likewise).

The only thing I can find that helps is to declare, for example,

type base_thing_type is (invalid, something1,something2,something3,something4,something5,something6);
for base_thing_type use (invalid => 0, something1 => 1,something2 => 2,something3 =>
                      3,something4 => 4,something5 => 5,something6 => 6);
for base_thing_type'size use 32;
type thing_type is new base_thing_type range something1 .. something6;
Simon Wright
  • 25,108
  • 2
  • 35
  • 62
  • Thank you Simon, I'll submit a bug report to GCC. – Kevin Mar 16 '17 at 17:20
  • Kevin, did you ever report this bug? it’s still present in GCC 8.0.0 20171216 – Simon Wright Jan 17 '18 at 17:55
  • This bug is present also in GNAT 8.3 (the one from Debian buster) but not in GNAT 9.3 (the one from Ubuntu 20.04). On this particular example it has been fixed, but on some of my applications the 9.3 (or CE 2020) raises other nonsense "invalid data" (which did not raise in 8.3!). – maxime-esa Jul 26 '20 at 10:26
4

It looks like a bug in GCC/GNAT. I can replicate the incorrect behaviour with GNAT-GPL-2016 in standard compliant mode (-gnato -fstack-check -gnat12). The critical part seems to be that Something1 is represented as 1 instead of the more typical 0. I suggest that you report the bug to the GCC developers.

Jacob Sparre Andersen
  • 6,733
  • 17
  • 22