From 9d23dab9e41be49a1568a55463828fd68a4c2538 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Wed, 26 Nov 2025 13:18:13 +0100 Subject: [PATCH 1/5] [h2root] Adapt to GCC 8 passing convention for string length According to the `gfortran` argument passing conventions, for any Fortran procedure, the compiler will automatically define a C prototype. This is what we use in `h2root`. Note that for procedures like `HROPEN` that takes string arguments, the signature of the C prototype will have extra arguments for the string lengths, which we also have to include in our forward declaration and usage. However, the type of these was changed with GCC 8 to size_t, so we have to also account for that as recommended in [1]. Otherwise, we get undefined behavor, which causes the `h2root` test to fail on ARM64 with GCC 14. [1] https://gcc.gnu.org/onlinedocs/gfortran/Argument-passing-conventions.html (cherry picked from commit aafddfbb1c6f44c135c3f172d7cf5d9ac5d7f79c) (cherry picked from commit f10c0acff150d3eb82892d208e40ba2c581de2e5) --- main/src/h2root.cxx | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/main/src/h2root.cxx b/main/src/h2root.cxx index b374c16c2ffaf..54dec7e7765e2 100644 --- a/main/src/h2root.cxx +++ b/main/src/h2root.cxx @@ -131,6 +131,15 @@ void MAIN__() {} # define type_of_call # define DEFCHAR const char* # define PASSCHAR(string) string + +// As recommended in +// https://gcc.gnu.org/onlinedocs/gfortran/Argument-passing-conventions.html +#if __GNUC__ > 7 +typedef size_t fortran_charlen_t; +#else +typedef int fortran_charlen_t; +#endif + #else # define hlimit HLIMIT # define hropen HROPEN @@ -169,7 +178,7 @@ void MAIN__() {} extern "C" void type_of_call hlimit(const int&); #ifndef WIN32 extern "C" void type_of_call hropen(const int&,DEFCHAR,DEFCHAR,DEFCHAR, - const int&,const int&,const int,const int,const int); + const int&,const int&,fortran_charlen_t,fortran_charlen_t,fortran_charlen_t); #else extern "C" void type_of_call hropen(const int&,DEFCHAR,DEFCHAR,DEFCHAR, const int&,const int&); @@ -179,7 +188,7 @@ extern "C" void type_of_call hrin(const int&,const int&,const int&); extern "C" void type_of_call hnoent(const int&,const int&); #ifndef WIN32 extern "C" void type_of_call hgive(const int&,DEFCHAR,const int&,const float&,const float&, - const int&,const float&,const float&,const int&,const int&,const int); + const int&,const float&,const float&,const int&,const int&,fortran_charlen_t); #else extern "C" void type_of_call hgive(const int&,DEFCHAR,const int&,const float&,const float&, const int&,const float&,const float&,const int&,const int&); @@ -187,20 +196,20 @@ extern "C" void type_of_call hgive(const int&,DEFCHAR,const int&,const float&,c #ifndef WIN32 extern "C" void type_of_call hgiven(const int&,DEFCHAR,const int&,DEFCHAR, - const float&,const float&,const int,const int); + const float&,const float&,fortran_charlen_t,fortran_charlen_t); #else extern "C" void type_of_call hgiven(const int&,DEFCHAR,const int&,DEFCHAR, const float&,const float&); #endif #ifndef WIN32 -extern "C" void type_of_call hntvar2(const int&,const int&,DEFCHAR,DEFCHAR,DEFCHAR,int&,int&,int&,int&,int&,const int,const int, const int); +extern "C" void type_of_call hntvar2(const int&,const int&,DEFCHAR,DEFCHAR,DEFCHAR,int&,int&,int&,int&,int&,fortran_charlen_t,fortran_charlen_t,fortran_charlen_t); #else extern "C" void type_of_call hntvar2(const int&,const int&,DEFCHAR,DEFCHAR,DEFCHAR,int&,int&,int&,int&,int&); #endif #ifndef WIN32 -extern "C" void type_of_call hbnam(const int&,DEFCHAR,const int&,DEFCHAR,const int&,const int, const int); +extern "C" void type_of_call hbnam(const int&,DEFCHAR,const int&,DEFCHAR,const int&,fortran_charlen_t,fortran_charlen_t); #else extern "C" void type_of_call hbnam(const int&,DEFCHAR,const int&,DEFCHAR,const int&); #endif @@ -232,14 +241,14 @@ extern "C" double type_of_call hije(const int&,const int&,const int&); #endif #ifndef WIN32 -extern "C" void type_of_call hcdir(DEFCHAR,DEFCHAR ,const int,const int); +extern "C" void type_of_call hcdir(DEFCHAR,DEFCHAR ,fortran_charlen_t,fortran_charlen_t); #else extern "C" void type_of_call hcdir(DEFCHAR,DEFCHAR); #endif extern "C" void type_of_call zitoh(const int&,const int&,const int&); #ifndef WIN32 -extern "C" void type_of_call uhtoc(const int&,const int&,DEFCHAR,int&,const int); +extern "C" void type_of_call uhtoc(const int&,const int&,DEFCHAR,int&,fortran_charlen_t); #else extern "C" void type_of_call uhtoc(const int&,const int&,DEFCHAR,int&); #endif From 8d88adf646d56c99f66a4847c5d47e461e1854e8 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Mon, 1 Dec 2025 19:47:03 +0100 Subject: [PATCH 2/5] [h2root] Adapt to GCC 8 passing convention for string length Follow-up of https://github.com/root-project/root/commit/aafddfbb1c6f44c135c3f172d7cf5d9ac5d7f79c (cherry picked from commit 34af31ca2f895ace0428f30fb923470cfabcf506) (cherry picked from commit bcdd4fbc5efd3d494a4d4cd6716657601648c3cf) --- main/src/h2root.cxx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/main/src/h2root.cxx b/main/src/h2root.cxx index 54dec7e7765e2..57d77a3c74a86 100644 --- a/main/src/h2root.cxx +++ b/main/src/h2root.cxx @@ -215,10 +215,18 @@ extern "C" void type_of_call hbnam(const int&,DEFCHAR,const int&,DEFCHAR,const #endif extern "C" void type_of_call hprntu(const int&); -extern "C" void type_of_call hgnpar(const int&,const char *,const int); +#ifndef WIN32 +extern "C" void type_of_call hgnpar(const int&,DEFCHAR,fortran_charlen_t); +#else +extern "C" void type_of_call hgnpar(const int&,DEFCHAR); +#endif extern "C" void type_of_call hgnf(const int&,const int&,const float&,const int&); extern "C" void type_of_call hgnt(const int&,const int&,const int&); -extern "C" void type_of_call rzink(const int&,const int&,const char *,const int); +#ifndef WIN32 +extern "C" void type_of_call rzink(const int&,const int&,DEFCHAR,fortran_charlen_t); +#else +extern "C" void type_of_call rzink(const int&,const int&,DEFCHAR); +#endif extern "C" void type_of_call hdcofl(); extern "C" void type_of_call hmaxim(const int&,const float&); extern "C" void type_of_call hminim(const int&,const float&); From daab9135f9c3bb9746bc5ae1e0c38f96ca1e6cf7 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 27 Feb 2026 10:37:42 +0100 Subject: [PATCH 3/5] Fix argument passing conventions in h2root. When variable-length strings are passed into functions compiled by gfortran, the lengths of the strings have to be passed at the end of the argument list as size_t. When using gcc <= 7 or clang (where the __GNUC__ macro might return unpredictable values), we were putting int on the C side, which got interpreted as size_t on the fortran side. (cherry picked from commit 3a9316ed1ddb4f0655d8d979181819e94c877048) (cherry picked from commit 575fa7d4ac0eedb7ff63520a18753a1f1f7b7997) --- main/src/h2root.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/main/src/h2root.cxx b/main/src/h2root.cxx index 57d77a3c74a86..c0ca8d5f0db44 100644 --- a/main/src/h2root.cxx +++ b/main/src/h2root.cxx @@ -134,11 +134,7 @@ void MAIN__() {} // As recommended in // https://gcc.gnu.org/onlinedocs/gfortran/Argument-passing-conventions.html -#if __GNUC__ > 7 -typedef size_t fortran_charlen_t; -#else -typedef int fortran_charlen_t; -#endif +using fortran_charlen_t = size_t; #else # define hlimit HLIMIT @@ -329,7 +325,11 @@ int main(int argc, char **argv) int lun = 10; #ifndef WIN32 - hropen(lun,PASSCHAR("example"),PASSCHAR(file_in),PASSCHAR("px"),record_size,ier,7,strlen(file_in),2); + // Reminder: Argument passing convention is that string lengths go as hidden arguments + // at the end of the argument list. + constexpr auto chdir = "example"; + constexpr auto opt = "px"; + hropen(lun, chdir, file_in, opt, record_size, ier, strlen(chdir), strlen(file_in), strlen(opt)); #else hropen(lun,PASSCHAR("example"),PASSCHAR(file_in),PASSCHAR("px"),record_size,ier); #endif From 772d9cdf1489a51624a5861abbca34069b308003 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Wed, 26 Nov 2025 19:13:17 +0100 Subject: [PATCH 4/5] [hbook] Adapt to GCC 8 passing convention for string length Follow-up of https://github.com/root-project/root/pull/20535 (cherry picked from commit 4ac2999b138f953ee1a291786b44546a70e212ca) (cherry picked from commit 3c3717f1f8c166a4323a8e3ee3c8c4027f950c38) --- hist/hbook/src/THbookFile.cxx | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/hist/hbook/src/THbookFile.cxx b/hist/hbook/src/THbookFile.cxx index fa86b23cc900d..2362b3c008260 100644 --- a/hist/hbook/src/THbookFile.cxx +++ b/hist/hbook/src/THbookFile.cxx @@ -137,6 +137,15 @@ static Int_t gLastEntry = -1; # define type_of_call # define DEFCHAR const char* # define PASSCHAR(string) string + +// As recommended in +// https://gcc.gnu.org/onlinedocs/gfortran/Argument-passing-conventions.html +#if __GNUC__ > 7 +typedef size_t fortran_charlen_t; +#else +typedef int fortran_charlen_t; +#endif + #else # define hlimit HLIMIT # define hldir HLDIR @@ -177,8 +186,8 @@ static Int_t gLastEntry = -1; extern "C" void type_of_call hlimit(const int&); #ifndef WIN32 extern "C" void type_of_call hropen(const int&,DEFCHAR,DEFCHAR,DEFCHAR, - const int&,const int&,const int,const int,const int); -extern "C" void type_of_call hrend(DEFCHAR,const int); + const int&,const int&,fortran_charlen_t,fortran_charlen_t,fortran_charlen_t); +extern "C" void type_of_call hrend(DEFCHAR,fortran_charlen_t); #else extern "C" void type_of_call hropen(const int&,DEFCHAR,DEFCHAR,DEFCHAR, const int&,const int&); @@ -189,7 +198,7 @@ extern "C" void type_of_call hrin(const int&,const int&,const int&); extern "C" void type_of_call hnoent(const int&,const int&); #ifndef WIN32 extern "C" void type_of_call hgive(const int&,DEFCHAR,const int&,const float&,const float&, - const int&,const float&,const float&,const int&,const int&,const int); + const int&,const float&,const float&,const int&,const int&,fortran_charlen_t); #else extern "C" void type_of_call hgive(const int&,DEFCHAR,const int&,const float&,const float&, const int&,const float&,const float&,const int&,const int&); @@ -198,8 +207,8 @@ extern "C" void type_of_call hgive(const int&,DEFCHAR,const int&,const float&,c //SUBROUTINE HGNT1(IDD,BLKNA1,VAR,IOFFST,NVAR,IDNEVT,IERROR) #ifndef WIN32 extern "C" void type_of_call hgiven(const int&,DEFCHAR,const int&,DEFCHAR, - const float&,const float&,const int,const int); -extern "C" void type_of_call hgnt1(const int&,DEFCHAR,DEFCHAR,const int&,const int&,const int&,const int&,const int,const int); + const float&,const float&,fortran_charlen_t,fortran_charlen_t); +extern "C" void type_of_call hgnt1(const int&,DEFCHAR,DEFCHAR,const int&,const int&,const int&,const int&,fortran_charlen_t,fortran_charlen_t); #else extern "C" void type_of_call hgiven(const int&,DEFCHAR,const int&,DEFCHAR, const float&,const float&); @@ -207,15 +216,15 @@ extern "C" void type_of_call hgnt1(const int&,DEFCHAR,DEFCHAR,const int&,const #endif #ifndef WIN32 -extern "C" void type_of_call hntvar2(const int&,const int&,DEFCHAR,DEFCHAR,DEFCHAR,int&,int&,int&,int&,int&,const int,const int, const int); -extern "C" void type_of_call hntvar3(const int&,const int&,DEFCHAR, const int); +extern "C" void type_of_call hntvar2(const int&,const int&,DEFCHAR,DEFCHAR,DEFCHAR,int&,int&,int&,int&,int&,fortran_charlen_t,fortran_charlen_t, fortran_charlen_t); +extern "C" void type_of_call hntvar3(const int&,const int&,DEFCHAR, fortran_charlen_t); #else extern "C" void type_of_call hntvar2(const int&,const int&,DEFCHAR,DEFCHAR,DEFCHAR,int&,int&,int&,int&,int&); extern "C" void type_of_call hntvar3(const int&,const int&,DEFCHAR); #endif #ifndef WIN32 -extern "C" void type_of_call hbnam(const int&,DEFCHAR,const int&,DEFCHAR,const int&,const int, const int); +extern "C" void type_of_call hbnam(const int&,DEFCHAR,const int&,DEFCHAR,const int&,fortran_charlen_t, fortran_charlen_t); #else extern "C" void type_of_call hbnam(const int&,DEFCHAR,const int&,DEFCHAR,const int&); #endif @@ -237,8 +246,8 @@ extern "C" void type_of_call hix(const int&,const int&,const float&); extern "C" void type_of_call hijxy(const int&,const int&,const int&,const float&,const float&); extern "C" float type_of_call hije(const int&,const int&,const int&); #ifndef WIN32 -extern "C" void type_of_call hcdir(DEFCHAR,DEFCHAR ,const int,const int); -extern "C" void type_of_call hldir(DEFCHAR,DEFCHAR ,const int,const int); +extern "C" void type_of_call hcdir(DEFCHAR,DEFCHAR ,fortran_charlen_t,fortran_charlen_t); +extern "C" void type_of_call hldir(DEFCHAR,DEFCHAR ,fortran_charlen_t,fortran_charlen_t); #else extern "C" void type_of_call hcdir(DEFCHAR,DEFCHAR); extern "C" void type_of_call hldir(DEFCHAR,DEFCHAR); From 1a059e1f7c1e46099e8e739ff2c7edc7b78d44a8 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Fri, 27 Feb 2026 10:37:42 +0100 Subject: [PATCH 5/5] Fix argument passing conventions in THbookFile. When variable-length strings are passed into functions compiled by gfortran, the lengths of the strings have to be passed at the end of the argument list as size_t. When using gcc <= 7 or clang (where the __GNUC__ macro might return unpredictable values), we were putting int on the C side, which got interpreted as size_t on the fortran side. (cherry picked from commit 19fdba0a951f6a0dd2126b4a701a1e3964c9c812) (cherry picked from commit ed8a5dd650830decc15f59c843b3b4e3ff32e7c2) --- hist/hbook/src/THbookFile.cxx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/hist/hbook/src/THbookFile.cxx b/hist/hbook/src/THbookFile.cxx index 2362b3c008260..d7fa9cc0a3e3c 100644 --- a/hist/hbook/src/THbookFile.cxx +++ b/hist/hbook/src/THbookFile.cxx @@ -140,11 +140,7 @@ static Int_t gLastEntry = -1; // As recommended in // https://gcc.gnu.org/onlinedocs/gfortran/Argument-passing-conventions.html -#if __GNUC__ > 7 -typedef size_t fortran_charlen_t; -#else -typedef int fortran_charlen_t; -#endif +using fortran_charlen_t = size_t; #else # define hlimit HLIMIT