mirror of
https://github.com/AdaCore/aws.git
synced 2026-02-12 12:29:46 -08:00
Fix creation of Huffman decoding tree for big-endian platforms
Attempting to run demos/hello_world on ppc-linux yields a constraint error
at startup:
> raised CONSTRAINT_ERROR : aws-http2-hpack-huffman.adb:358 discriminant check failed
This occurs during the elaboration of AWS.HTTP2.HPACK.Huffman, in
Create_Tree.Insert_Item: we reach a point where we expect a non-leaf node
and attempt to access its children via .LR, but we actually get a leaf node.
This can be traced back to ppc-linux being a big-endian platform, and the
iteration over C.Bits being sensitive to endianness. Since we alias an
Unsigned_32 as a Word_Bits array, the bit order will depend on the platform
representation. Consider this example:
-- alias.adb
with Ada.Text_IO;
with Ada.Integer_Text_IO;
with Interfaces;
use Interfaces;
procedure Alias is
subtype Bit is Integer range 0 .. 1;
type Word_Bits is array (0 .. 31) of Bit with Pack;
package U32_IO is new Ada.Text_IO.Modular_IO (Interfaces.Unsigned_32);
Foo : Interfaces.Unsigned_32 := 16#04030201#;
Bar : Word_Bits with Size => 32, Address => Foo'Address;
begin
U32_IO.Put (Foo, Base => 16);
Ada.Text_IO.New_Line;
U32_IO.Put (Foo, Base => 2);
Ada.Text_IO.New_Line;
for B in Bar'Range loop
U32_IO.Put (Interfaces.Shift_Right (Foo, B) and 1, Width => 1);
if B mod 8 = 7 then
Ada.Text_IO.Put(' ');
end if;
end loop;
Ada.Text_IO.New_Line;
for B in Bar'Range loop
Ada.Integer_Text_IO.Put (Bar (B), Width => 1);
if B mod 8 = 7 then
Ada.Text_IO.Put(' ');
end if;
end loop;
Ada.Text_IO.New_Line;
end Alias;
On x86_64-linux, this prints:
16#4030201#
2#100000000110000001000000001#
10000000 01000000 11000000 00100000
10000000 01000000 11000000 00100000
Whereas on ppc-linux, we get instead:
16#4030201#
2#100000000110000001000000001#
10000000 01000000 11000000 00100000
00000100 00000011 00000010 00000001
From this, we can observe:
* that Modular_IO's representation is always big-endian, with leading zeroes
suppressed:
* in base 16, we always get 16#(0)4#, then 16#03#, etc,
* in base 2, we always get 2#(00000)100#, then 2#00000011#, etc;
* that the results of shifting are platform-independent: a shift operates on
the numerical value of the integer; whatever endianness a CPU uses, it
will always implement a right-shift so that X>>n = X/(2^n);
* that aliasing an Unsigned_32 as an array of bits exposes the platform
endianness: a different endianness leads to a different bit order.
While it is not obvious why changing the iteration order over C.Bits
invalidates Create_Tree.Insert_Item's graph traversal, to the point of
mistaking a leaf node for a branch node, fixing this order does let this
elaboration code run to completion on ppc-linux, and introduces no
regression when running the testsuite on x86_64-linux.
This bug could also have been fixed by sprinkling Scalar_Storage_Order and
Bit_Order representation clauses over Word_Bits and Code; going with shifts
felt more straightforward.
TN: W214-015
This commit is contained in:
@@ -329,7 +329,6 @@ package body AWS.HTTP2.HPACK.Huffman is
|
||||
-----------------
|
||||
|
||||
procedure Create_Tree is
|
||||
type Word_Bits is array (0 .. 31) of Bit with Pack;
|
||||
|
||||
procedure Insert_Item (K : Unsigned_16);
|
||||
|
||||
@@ -339,14 +338,11 @@ package body AWS.HTTP2.HPACK.Huffman is
|
||||
|
||||
procedure Insert_Item (K : Unsigned_16) is
|
||||
C : constant Code := Table (K);
|
||||
H : Unsigned_32 := C.Bits;
|
||||
Bits : Word_Bits with Size => 32, Address => H'Address;
|
||||
|
||||
Iter : access Node_Access := Root'Access;
|
||||
begin
|
||||
for K in reverse 0 .. C.N_Bit - 1 loop
|
||||
declare
|
||||
B : constant Bit := Bits (K);
|
||||
B : constant Bit := Bit (Shift_Right (C.Bits, K) and 1);
|
||||
begin
|
||||
if Iter.all = null then
|
||||
Iter.all := new Node'(False, LR => (null, null));
|
||||
|
||||
Reference in New Issue
Block a user