From 9dd3addc0cceb90f8489be51bba84211ed2ead4d Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Tue, 5 Nov 2024 23:18:55 +0100 Subject: [PATCH] [3.13] gh-89640: harden float word ordering (#125571 and #126387) (#126429) Properly detect float word ordering on Linux (gh-125571) autoconf-archive patch by Dan Amelang. (cherry picked from commit 26d627779f79d8d5650fe7be348432eccc28f8f9) Hardcode WASM float word ordering to little endian (gh-126387) (cherry picked from commit 532fc08102d62c04d55f5b8aac00bd9e7e12ff4b) --- .github/workflows/build.yml | 2 +- ...4-10-16-09-37-51.gh-issue-89640.UDsW-j.rst | 2 + ...4-11-04-09-42-04.gh-issue-89640.QBv05o.rst | 1 + Tools/build/regen-configure.sh | 2 +- aclocal.m4 | 61 +++++++++++++++-- configure | 66 ++++++++++--------- configure.ac | 42 ++++++------ pyconfig.h.in | 4 -- 8 files changed, 114 insertions(+), 66 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2024-10-16-09-37-51.gh-issue-89640.UDsW-j.rst create mode 100644 Misc/NEWS.d/next/Build/2024-11-04-09-42-04.gh-issue-89640.QBv05o.rst diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 56940d7b4aa..763c5ade7eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -89,7 +89,7 @@ jobs: # reproducible: to get the same tools versions (autoconf, aclocal, ...) runs-on: ubuntu-24.04 container: - image: ghcr.io/python/autoconf:2024.10.11.11293396815 + image: ghcr.io/python/autoconf:2024.10.16.11360930377 timeout-minutes: 60 needs: check_source if: needs.check_source.outputs.run_tests == 'true' diff --git a/Misc/NEWS.d/next/Build/2024-10-16-09-37-51.gh-issue-89640.UDsW-j.rst b/Misc/NEWS.d/next/Build/2024-10-16-09-37-51.gh-issue-89640.UDsW-j.rst new file mode 100644 index 00000000000..5aba2c789b6 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2024-10-16-09-37-51.gh-issue-89640.UDsW-j.rst @@ -0,0 +1,2 @@ +Improve detection of float word ordering on Linux when link-time optimizations +are enabled. diff --git a/Misc/NEWS.d/next/Build/2024-11-04-09-42-04.gh-issue-89640.QBv05o.rst b/Misc/NEWS.d/next/Build/2024-11-04-09-42-04.gh-issue-89640.QBv05o.rst new file mode 100644 index 00000000000..4fa44a1d649 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2024-11-04-09-42-04.gh-issue-89640.QBv05o.rst @@ -0,0 +1 @@ +Hard-code float word ordering as little endian on WASM. diff --git a/Tools/build/regen-configure.sh b/Tools/build/regen-configure.sh index a267cfb7f5c..e1ecefddeb8 100755 --- a/Tools/build/regen-configure.sh +++ b/Tools/build/regen-configure.sh @@ -5,7 +5,7 @@ set -e -x # The check_autoconf_regen job of .github/workflows/build.yml must kept in # sync with this script. Use the same container image than the job so the job # doesn't need to run autoreconf in a container. -IMAGE="ghcr.io/python/autoconf:2024.10.06.11200919239" +IMAGE="ghcr.io/python/autoconf:2024.10.16.11360930377" AUTORECONF="autoreconf -ivf -Werror" WORK_DIR="/src" diff --git a/aclocal.m4 b/aclocal.m4 index 832aec19f48..b082a5b1bc5 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -41,32 +41,81 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun # If neither value is found, the user is instructed to specify the # ordering. # +# Early versions of this macro (i.e., before serial 12) would not work +# when interprocedural optimization (via link-time optimization) was +# enabled. This would happen when, say, the GCC/clang "-flto" flag, or the +# ICC "-ipo" flag was used, for example. The problem was that under +# these conditions, the compiler did not allocate for and write the special +# float value in the data segment of the object file, since doing so might +# not prove optimal once more context was available. Thus, the special value +# (in platform-dependent binary form) could not be found in the object file, +# and the macro would fail. +# +# The solution to the above problem was to: +# +# 1) Compile and link a whole test program rather than just compile an +# object file. This ensures that we reach the point where even an +# interprocedural optimizing compiler writes values to the data segment. +# +# 2) Add code that requires the compiler to write the special value to +# the data segment, as opposed to "optimizing away" the variable's +# allocation. This could be done via compiler keywords or options, but +# it's tricky to make this work for all versions of all compilers with +# all optimization settings. The chosen solution was to make the exit +# code of the test program depend on the storing of the special value +# in memory (in the data segment). Because the exit code can be +# verified, any compiler that aspires to be correct will produce a +# program binary that contains the value, which the macro can then find. +# +# How does the exit code depend on the special value residing in memory? +# Memory, unlike variables and registers, can be addressed indirectly at run +# time. The exit code of this test program is a result of indirectly reading +# and writing to the memory region where the special value is supposed to +# reside. The actual memory addresses used and the values to be written are +# derived from the the program input ("argv") and are therefore not known at +# compile or link time. The compiler has no choice but to defer the +# computation to run time, and to prepare by allocating and populating the +# data segment with the special value. For further details, refer to the +# source code of the test program. +# +# Note that the test program is never meant to be run. It only exists to host +# a double float value in a given platform's binary format. Thus, error +# handling is not included. +# # LICENSE # -# Copyright (c) 2008 Daniel Amelang +# Copyright (c) 2008, 2023 Daniel Amelang # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 11 +#serial 12 AC_DEFUN([AX_C_FLOAT_WORDS_BIGENDIAN], [AC_CACHE_CHECK(whether float word ordering is bigendian, ax_cv_c_float_words_bigendian, [ ax_cv_c_float_words_bigendian=unknown -AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ +AC_LINK_IFELSE([AC_LANG_SOURCE([[ -double d = 90904234967036810337470478905505011476211692735615632014797120844053488865816695273723469097858056257517020191247487429516932130503560650002327564517570778480236724525140520121371739201496540132640109977779420565776568942592.0; +#include + +static double m[] = {9.090423496703681e+223, 0.0}; + +int main (int argc, char *argv[]) +{ + m[atoi (argv[1])] += atof (argv[2]); + return m[atoi (argv[3])] > 0.0; +} ]])], [ -if grep noonsees conftest.$ac_objext >/dev/null ; then +if grep noonsees conftest$EXEEXT >/dev/null ; then ax_cv_c_float_words_bigendian=yes fi -if grep seesnoon conftest.$ac_objext >/dev/null ; then +if grep seesnoon conftest$EXEEXT >/dev/null ; then if test "$ax_cv_c_float_words_bigendian" = unknown; then ax_cv_c_float_words_bigendian=no else diff --git a/configure b/configure index 9057cebd16d..5295bdab6c2 100755 --- a/configure +++ b/configure @@ -23703,18 +23703,26 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -double d = 90904234967036810337470478905505011476211692735615632014797120844053488865816695273723469097858056257517020191247487429516932130503560650002327564517570778480236724525140520121371739201496540132640109977779420565776568942592.0; +#include + +static double m[] = {9.090423496703681e+223, 0.0}; + +int main (int argc, char *argv[]) +{ + m[atoi (argv[1])] += atof (argv[2]); + return m[atoi (argv[3])] > 0.0; +} _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : -if grep noonsees conftest.$ac_objext >/dev/null ; then +if grep noonsees conftest$EXEEXT >/dev/null ; then ax_cv_c_float_words_bigendian=yes fi -if grep seesnoon conftest.$ac_objext >/dev/null ; then +if grep seesnoon conftest$EXEEXT >/dev/null ; then if test "$ax_cv_c_float_words_bigendian" = unknown; then ax_cv_c_float_words_bigendian=no else @@ -23724,7 +23732,8 @@ fi fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_c_float_words_bigendian" >&5 printf "%s\n" "$ax_cv_c_float_words_bigendian" >&6; } @@ -23732,41 +23741,34 @@ printf "%s\n" "$ax_cv_c_float_words_bigendian" >&6; } case $ax_cv_c_float_words_bigendian in yes) -printf "%s\n" "#define FLOAT_WORDS_BIGENDIAN 1" >>confdefs.h +printf "%s\n" "#define DOUBLE_IS_BIG_ENDIAN_IEEE754 1" >>confdefs.h ;; no) - ;; + +printf "%s\n" "#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754 1" >>confdefs.h + ;; *) - as_fn_error $? " + case $host_cpu in #( + *arm*) : + # Some ARM platforms use a mixed-endian representation for + # doubles. While Python doesn't currently have full support + # for these platforms (see e.g., issue 1762561), we can at + # least make sure that float <-> string conversions work. + # FLOAT_WORDS_BIGENDIAN doesn't actually detect this case, + # but if it's not big or little, then it must be this? -Unknown float word ordering. You need to manually preset -ax_cv_c_float_words_bigendian=no (or yes) according to your system. +printf "%s\n" "#define DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 1" >>confdefs.h + ;; #( + wasm*) : - " "$LINENO" 5 ;; +printf "%s\n" "#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754 1" >>confdefs.h + ;; #( + *) : + ;; +esac ;; esac -if test "$ax_cv_c_float_words_bigendian" = "yes" -then - -printf "%s\n" "#define DOUBLE_IS_BIG_ENDIAN_IEEE754 1" >>confdefs.h - -elif test "$ax_cv_c_float_words_bigendian" = "no" -then - -printf "%s\n" "#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754 1" >>confdefs.h - -else - # Some ARM platforms use a mixed-endian representation for doubles. - # While Python doesn't currently have full support for these platforms - # (see e.g., issue 1762561), we can at least make sure that float <-> string - # conversions work. - # FLOAT_WORDS_BIGENDIAN doesn't actually detect this case, but if it's not big - # or little, then it must be this? - -printf "%s\n" "#define DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754 1" >>confdefs.h - -fi # The short float repr introduced in Python 3.1 requires the # correctly-rounded string <-> double conversion functions from diff --git a/configure.ac b/configure.ac index 0fc039e3d61..a3d7ab904bd 100644 --- a/configure.ac +++ b/configure.ac @@ -5856,28 +5856,26 @@ AS_VAR_IF([ac_cv_gcc_asm_for_x64], [yes], [ # * Check for various properties of floating point * # ************************************************** -AX_C_FLOAT_WORDS_BIGENDIAN -if test "$ax_cv_c_float_words_bigendian" = "yes" -then - AC_DEFINE([DOUBLE_IS_BIG_ENDIAN_IEEE754], [1], - [Define if C doubles are 64-bit IEEE 754 binary format, stored - with the most significant byte first]) -elif test "$ax_cv_c_float_words_bigendian" = "no" -then - AC_DEFINE([DOUBLE_IS_LITTLE_ENDIAN_IEEE754], [1], - [Define if C doubles are 64-bit IEEE 754 binary format, stored - with the least significant byte first]) -else - # Some ARM platforms use a mixed-endian representation for doubles. - # While Python doesn't currently have full support for these platforms - # (see e.g., issue 1762561), we can at least make sure that float <-> string - # conversions work. - # FLOAT_WORDS_BIGENDIAN doesn't actually detect this case, but if it's not big - # or little, then it must be this? - AC_DEFINE([DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754], [1], - [Define if C doubles are 64-bit IEEE 754 binary format, stored - in ARM mixed-endian order (byte order 45670123)]) -fi +AX_C_FLOAT_WORDS_BIGENDIAN( + [AC_DEFINE([DOUBLE_IS_BIG_ENDIAN_IEEE754], [1], + [Define if C doubles are 64-bit IEEE 754 binary format, + stored with the most significant byte first])], + [AC_DEFINE([DOUBLE_IS_LITTLE_ENDIAN_IEEE754], [1], + [Define if C doubles are 64-bit IEEE 754 binary format, + stored with the least significant byte first])], + [AS_CASE([$host_cpu], + [*arm*], [# Some ARM platforms use a mixed-endian representation for + # doubles. While Python doesn't currently have full support + # for these platforms (see e.g., issue 1762561), we can at + # least make sure that float <-> string conversions work. + # FLOAT_WORDS_BIGENDIAN doesn't actually detect this case, + # but if it's not big or little, then it must be this? + AC_DEFINE([DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754], [1], + [Define if C doubles are 64-bit IEEE 754 binary format, + stored in ARM mixed-endian order (byte order 45670123)])], + [wasm*], [AC_DEFINE([DOUBLE_IS_LITTLE_ENDIAN_IEEE754], [1], + [Define if C doubles are 64-bit IEEE 754 binary format, + stored with the least significant byte first])])]) # The short float repr introduced in Python 3.1 requires the # correctly-rounded string <-> double conversion functions from diff --git a/pyconfig.h.in b/pyconfig.h.in index 4d8b1d4f254..4531dadee38 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -47,10 +47,6 @@ /* Define if --enable-ipv6 is specified */ #undef ENABLE_IPV6 -/* Define to 1 if your system stores words within floats with the most - significant word first */ -#undef FLOAT_WORDS_BIGENDIAN - /* Define if getpgrp() must be called as getpgrp(0). */ #undef GETPGRP_HAVE_ARG