I've encountered an issue where using modular types in Ada that are not divisible by the system's Storage_Unit
( as defined in the runtime's system.ads
) will raise a Constraint_Error
at runtime when accessed. I originally encountered this issue working on an bare-metal system using a minimal runtime while trying to read 12bit values from a buffer by overlaying the 12bit array over the buffer in memory. Does anyone know why this is occurring?
The following minimal example illustrates the issue I'm encountering. I tested this using AdaCore's GNAT 2019, compiled with the included zfp
runtime. Using the standard runtime does not reproduce the issue.
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
----------------------------------------------------------------------------
-- Modular type with standard size divisible by 8.
----------------------------------------------------------------------------
type Type_One is mod 2 ** 16;
type Buffer_Type_One is array (1 .. 128) of Type_One;
----------------------------------------------------------------------------
-- Modular type with non-base 8 size.
----------------------------------------------------------------------------
type Type_Two is mod 2 ** 12;
type Buffer_Type_Two is array (1 .. 128) of Type_Two;
type Buffer is array (1 .. 256) of Character;
----------------------------------------------------------------------------
-- Example buffer.
----------------------------------------------------------------------------
Test_Buffer : Buffer := (others => ' ');
begin
----------------------------------------------------------------------------
-- Will not raise an exception.
----------------------------------------------------------------------------
Test_One :
declare
Buffer_One : Buffer_Type_One
with Import,
Convention => Ada,
Address => Test_Buffer'Address;
begin
Put_Line ("Testing type one");
for I in Natural range 1 .. 16 loop
Put_Line ("Test: " & Buffer_One (I)'Image);
end loop;
end Test_One;
----------------------------------------------------------------------------
-- Will raise a constraint error at runtime.
----------------------------------------------------------------------------
Test_Two :
declare
Buffer_Two : Buffer_Type_Two
with Import,
Convention => Ada,
Address => Test_Buffer'Address;
begin
Put_Line ("Testing type two");
for I in Natural range 1 .. 16 loop
Put_Line ("Test: " & Buffer_Two (I)'Image);
end loop;
exception
when Constraint_Error =>
Put_Line ("Constraint error encountered.");
end Test_Two;
end Main;
Here is the project file I used to compile this example:
project Test is
for Object_Dir use "obj";
for Exec_Dir use "build";
for Create_Missing_Dirs use "True";
for Languages use ("Ada");
package Builder is
for Executable ("main.adb") use "test";
end Builder;
for Main use ("main.adb");
package Compiler is
for Default_Switches ("Ada") use (
"-gnat2012",
"-gnatwadehl",
"-gnatVa",
"-gnaty3abcdefhiklmnoprstux"
);
end Compiler;
for Runtime ("Ada") use "zfp";
end Test;
I can't seem to find anything in the RM that would indicate why this would happen.
EDIT: Simon Wright below has figured out why this is happening. My naive understanding was that an instance of Buffer_Type_Two
overlaid at the specified memory address would interpret the memory at this location as a sequence of 12bit values. It appears that this is not the case. It appears as though the compiler is rounding the size of the type up to 16bits, then raising a Constraint_Error
when the 16bit value read from the array does not conform to the 12bit type.
If anyone can think of a better way to read a sequence of 12bit values from a location in memory in a sequential way I would greatly appreciate it, thank you.
size
aspect manually. The next thing I tried was to make the array typealiased
. Neither of these helped. – Thaumatropepragma Pack
and the appropriate size aspect? – AccessaryBuffer_Type_Two
without any representation clauses. A compiler is free to choose any valid representation unless a specific representation is specified. It would be perfectly valid for a compiler to use 32 bits for the components of your array types. If, as appears to bne the case, your compiler does not support the representation you desire, then you will have to manually extract the bits you need to create a value of your type. – Clotheshorse