Ada linking with C fails with a run-time error (from Rosetta Code)

Hi;

I’m hoping that someone can verify that the reply I received on the Rosetta Code web site (at the bottom of this posting) is the best course of action to take or not.

I get a run-time error: raised INTERFACES.C.STRINGS.UPDATE_ERROR : i-cstrin.adb:260
cat ./test_it.bash

!/bin/bash
gcc -v -c ./main.c gnatmake -v -c ./exported.adb gnatbind -v -n ./exported.ali gnatlink -v ./exported.ali ./main.o -o ./main ./main 2>&1 | tee ./NOTE.txt gnatclean ./exported rm ./main ./main.o

cat ./exported.ads

with Interfaces.C;          use Interfaces.C;
with Interfaces.C.Strings;  use Interfaces.C.Strings;

package Exported is
   function Query (Data : chars_ptr; Size : access size_t)
      return int;
   pragma Export (C, Query, "Query");
end Exported;

cat ./exported.adb

package body Exported is
   function Query (Data : chars_ptr; Size : access size_t)
      return int is
      Result : char_array := "Here am I";
   begin
      if Size.all < Result'Length then
         return 0;
      else
         Update (Data, 0, Result);
         Size.all := Result'Length;
         return 1;
      end if;
   end Query;
end Exported;

cat ./main.c

#include <stdio.h>

extern int Query (char * Data, size_t * Length);

int main (int argc, char * argv [])
{
   char     Buffer [1024];
   size_t   Size = sizeof (Buffer);

   if (0 == Query (Buffer, &Size))
   {
      printf ("failed to call Query\n");
   }
   else
   {
      char * Ptr = Buffer;
      while (Size-- > 0) putchar (*Ptr++);
      putchar ('\n');
   }
}

I have a lot of output (as I used the verbose flag on all of the build commands)…but none of it seems to point to a make and/or link error…I can provide the output if desired.

Environment: MacOS 14.6.1 M1 chip (arm64) gnatmake -v
GNATMAKE 14.1.0 Copyright (C) 1992-2024, Free Software Foundation, Inc.

Thanks, Retired Build Engineer

Response on the Rosetta Code web site talk page for this task:
I’m not that knowledgeable of Ada, but Googling ada update_error found this:
https://comp.lang.ada.narkive.com/EzyUTCFS/interfaces-c-string-update
which suggests you need to null terminate the string (which C would expect in general but probably not in this example) and probably set Check to false in the Update call.
–Tigerofdarkness (talk) 07:48, 14 September 2024 (UTC)

Thanks,
Retired Build Engineer

If you look at ARM B.3.1(57) you’ll find

Execution of Update is erroneous if Check is False and a call with Check equal to True would have propagated Update_Error.

… and, as you’ve found, this code falls into the “erroneous” category. (46) is where the failure occurs, because the C Buffer[1024] is uninitialized (I suspect it’s all zeros), so Update’s check that the proposed insertion won’t overflow the buffer fails.

The check that the proposed insertion isn’t longer than the passed Size means that telling Update not to check is actually OK, erroneous or not.

I think it’d be a Good Idea to nul-terminate Result : char_array, probably by calling To_C to initialize it, since who knows what the C Buffer contained before we started?


“Erroneous execution” is a term of art in Ada, ARM 1.1.5(10):

In addition to bounded errors, the language rules define certain kinds of errors as leading to erroneous execution . Like bounded errors, the implementation is not expected to detect such errors either prior to or during run time. Unlike bounded errors, there is no language-specified bound on the possible effect of erroneous execution; the effect is in general not predictable.

1 Like