[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1067453: gnat: Ada.Calendar.Clock crashes on time_t64 architectures



Source: gcc-13
Followup-For: Bug #1067453

The gettimeofday import issue seems specific to the time_t 64
transition in Debian.

When building C on armhf, a #define replaces gettimeofday with
__gettimeofday64 so the linker finds the 64 bits version in the libc.

When linking Ada code, the linker searches for the gettimeofday symbol
and links with the 32 bits version, as demonstrated by the reproducer
script below.  Here is the output.

./c_part
 timeval size: 128
 tv_sec   offset: 0   size: 64   value: 662A7756
 tv_usec   offset: 8   size: 64   value: 1C54
 56 77 2A 66 00 00 00 00 54 1C 00 00 00 00 00 00
./ada_part
 timeval size: 128
  tv_sec offset: 0   size: 64   value:16#27A9662A7756#
  tv_usec offset: 8   size: 64 value:-16#80B1C0708345E00#
 56 77 2A 66 A9 27 00 00 00 A2 CB F7 F8 E3 F4 F7

Changing the External_Name from "gettimeofday" to "__gettimeofday64"
fixes the mismatch (except for the lower microseconds of course).

./c_part
 81 76 2A 66 00 00 00 00 0F E2 0C 00 00 00 00 00
./ada_part
 81 76 2A 66 00 00 00 00 CB EC 0C 00 00 00 00 00

So we have two possible work-arounds.

 * build a C source with a __gnat_gettimeofday wrapper.
   This option, implemented by my last commit, patches
     gcc/ada/Makefile.rtl
     gcc/ada/cal.c
     gcc/ada/gcc-interface/Makefile.in
     gcc/ada/libgnat-s-osprim__posix.adb
   and interfers with the previous commit.

 * simply patch gcc/ada/libgnat/s-osprim__posix.adb with
-      pragma Import (C, gettimeofday, "gettimeofday");
+      pragma Import (C, gettimeofday, "__gettimeofday64");
  This seems better, but must only be applied on targets affected by
  the t64 transition.

I do not know which one is the best, but at least the second one
explains why the first one did work.

Just in case, here is the reproducer script:

--
#!/bin/sh
set -efuv

cat > hexdump.h <<EOF
extern void hexdump(char* p, int length);
EOF

cat > hexdump.c <<EOF
#include <stdio.h>
#include "hexdump.h"
void hexdump(char* p, int length)
{
  while (length--)
  {
    printf(" %02hhX", *p++);
  }
  printf("\n");
}
EOF

cat > c_part.c <<EOF
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include "hexdump.h"
int main(int argc, const char* argv[]) {
  struct timeval tv;
  if (argc == 1)
  {
    printf(" gettimeofday returned %i\n", gettimeofday(&tv, NULL));
    printf(" timeval size: %lli\n", (long long int)( CHAR_BIT * sizeof(tv)));
    printf(" tv_sec");
    printf("   offset: %lli", (long long int)((char*)(&(tv.tv_sec)) - (char*)(&tv)));
    printf("   size: %lli",   (long long int)(CHAR_BIT * sizeof(tv.tv_sec)));
    printf("   value: %llX",  (long long int)tv.tv_sec);
    printf("\n");
    printf(" tv_usec");
    printf("   offset: %lli", (long long int)((char*)(&(tv.tv_usec)) - (char*)(&tv)));
    printf("   size: %lli",   (long long int)(CHAR_BIT * sizeof(tv.tv_usec)));
    printf("   value: %llX",  (long long int)tv.tv_usec);
    printf("\n");
    hexdump((char*)(&tv), sizeof(tv));
  }
  else
  {
    printf("   time_t_bits      : constant := %lli;\n",
           (long long int)(CHAR_BIT * sizeof(tv.tv_sec)));
    printf("   suseconds_t_bits : constant := %lli;\n",
           (long long int)( CHAR_BIT * sizeof(tv.tv_usec)));
  }
  return EXIT_SUCCESS;
}
EOF

cat > ada_part.adb <<EOF
with Ada.Long_Long_Integer_Text_IO; use Ada.Long_Long_Integer_Text_IO;
with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C; use Interfaces.C;
with System; use System;
procedure Ada_Part is
$(./c_part 1)
   type time_t is range -2**(time_t_bits - 1) ..
                         2**(time_t_bits - 1) - 1 with Convention => C;
   type suseconds_t is range -2**(suseconds_t_bits - 1) ..
                              2**(suseconds_t_bits - 1) - 1
     with Convention => C;
   type timeval is record
      tv_sec  : time_t;
      tv_usec : suseconds_t;
   end record with Convention => C;
   function gettimeofday (tv : access timeval; tz : Address) return int
     with Import, Convention => C,
          External_Name => "gettimeofday";                             --  Here
   Tv : aliased timeval;
   function Offset (A, B : Address) return String is
     (Long_Long_Integer'Image (Long_Long_Integer'Value (A'Img)
                             - Long_Long_Integer'Value (B'Img)));
   I : constant int := gettimeofday(Tv'Access, Null_Address);
   procedure hexdump(p : Address; count : Integer)
     with Import, Convention => C, External_Name => "hexdump";
begin
  Put_Line (" gettimeofday returned" & I'Img);
  Put_Line (" timeval size:" & Integer'Image (Tv'Size));
  Put ("  tv_sec offset:" & Offset (Tv.tv_sec'Address, Tv'Address)
       & "   size:" & Integer'Image (Tv.tv_sec'Size)
       & "   value:");
  Put (Long_Long_Integer (Tv.tv_sec), Width => 0, Base => 16);
  New_Line;
  Put ("  tv_usec offset:" & Offset (Tv.tv_usec'Address, Tv'Address)
       & "   size:" & Integer'Image (Tv.tv_usec'Size)
       & " value:");
  Put (Long_Long_Integer (Tv.tv_usec), Width => 0, Base => 16);
  New_Line;
  hexdump (Tv'Address, Tv'Size / 8);
end Ada_Part;
EOF

gcc -c -Wall -Wextra hexdump.c -o hexdump.o
gcc -Wall -Wextra c_part.c hexdump.o -o c_part
gnatmake -gnat2022 -gnatwa -gnatya ada_part.adb -largs hexdump.o

./c_part
./ada_part


Reply to: