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: