โŒ About FreshRSS

Reading view

There are new articles available, click to refresh the page.

Importing C function which accepts array of union

I'm working on an Ada language binding for a C library and stumbled upon a function which expects an array of union values. I tried to used Unchecked_Union aspect without defining discriminant record but it didn't work because Ada doesn't accept unconstrained element type in array.

In C, function and union are declared something like this:

union argument {
    int32_t i;
    uint32_t u;
    fixed_t f;        // custom 24.8 floating point type, defined as int32_t
    const char *s;    // string
    struct object *o; // custom object type
    uint32_t n;       // may be set as id from struct object (o->id) 
    struct array *a;  // custom array type
    int32_t h;        // file descriptor
};

.. foo(.., union argument *args);

I'm using GNAT toolchain and running gcc with -fdump-ada-spec produced type:

type argument (discr : unsigned := 0) is record
   case discr is
      when 0 =>
         i : aliased x86_64_linux_gnu_bits_stdint_intn_h.int32_t;
      when 1 =>
         u : aliased x86_64_linux_gnu_bits_stdint_uintn_h.uint32_t;
      when 2 =>
         f : aliased fixed_t;
      when 3 =>
         s : Interfaces.C.Strings.chars_ptr;
      when 4 =>
         o : access object;
      when 5 =>
         n : aliased x86_64_linux_gnu_bits_stdint_uintn_h.uint32_t;
      when 6 =>
         a : access array;
      when others =>
         h : aliased x86_64_linux_gnu_bits_stdint_intn_h.int32_t;
   end case;
end record
with Convention => C_Pass_By_Copy,
     Unchecked_Union => True;

I replaced unsigned discriminant with enum type and it works fine when I use it as a single value, or as an array of unchecked unions with same discriminant value, but I can't figure out the proper way of using different union components in Ada. I do have some ideas to workaround this though, but I'm not sure if they are correct or possible to implement in Ada.

Observations:

  • C function internally expects at most 20 items in an array
  • There is a companion function with similar signature that uses varargs instead of array of union type, varags are then converted to that union type

Option 1 Use varargs version and generate in Ada several overloaded functions with different count/type combinations. IIUC, this will require 20 * 8 function definitions, not fun at all.

Option 2 Write an import function with definite union type and then somehow cast with Unchecked_Conversion to/from values, i.e. array (Integer range 0..19) of argument(4), then convert elements of an array to different types.

Option 3 Take advantage of max array size and allocate (aliased) memory blob of 20 * 64 bytes (union size), write helper procedures which will read/write correct values at correct memory locations, and then pass this blob either as 'Access or 'Address to the C function. In this case function parameter would be access my_blob or just System.Address.

I'm personally leaning towards option 3, but it'll require a considerable amount of research/work/testing so I'm asking if there are better ways to do that.

P.S. I think it is a defect on Ada side as ARM B.3.3 ยง14/2 clearly states that "All objects of an unchecked union type have the same size", so it should be possible to create an array of unchecked unions without defining discriminant. But I understand that it was done to make code safer to use.

โŒ