diff options
author | Jordan Henderson <jhenderson@hdfgroup.org> | 2024-03-01 23:20:49 (GMT) |
---|---|---|
committer | Jordan Henderson <jhenderson@hdfgroup.org> | 2024-03-01 23:30:49 (GMT) |
commit | 6965049700fa367d0cfe6fba211bac0ff53263ba (patch) | |
tree | 5a5305f3cae380a1619ce76003e62efc031d22e0 /src | |
parent | a793f30e2c5885d92d31484dc3d7319374c4d58b (diff) | |
download | hdf5-6965049700fa367d0cfe6fba211bac0ff53263ba.zip hdf5-6965049700fa367d0cfe6fba211bac0ff53263ba.tar.gz hdf5-6965049700fa367d0cfe6fba211bac0ff53263ba.tar.bz2 |
Fixed some _Float16 support issues
Fixed some conversion issues with Clang due to problematic undefined
behavior when casting a negative floating-point value to an integer
Fixed a bug in the library's software integer to floating-point
conversion function where a user's conversion exception function
returning H5T_CONV_UNHANDLED in the case of overflows would result in
incorrect data after conversion
Added configure checks for functions and macros related to _Float16
usage since some compilers expose the datatype but not the functions or
macros
Fixed a dt_arith test failure when H5_WANT_DCONV_EXCEPTION isn't defined
Fixed a few warnings from not explicitly casting some _Float16 variables
upwards
Diffstat (limited to 'src')
-rw-r--r-- | src/H5Tconv.c | 35 | ||||
-rw-r--r-- | src/H5private.h | 30 |
2 files changed, 52 insertions, 13 deletions
diff --git a/src/H5Tconv.c b/src/H5Tconv.c index 33852a9..d1cc307 100644 --- a/src/H5Tconv.c +++ b/src/H5Tconv.c @@ -753,14 +753,38 @@ { \ if (*(S) > (ST)(D_MAX)) \ *(D) = H5_GLUE3(H5T_NATIVE_, DTYPE, _POS_INF_g); \ - else if (*(S) < (ST)(D_MIN)) \ - *(D) = H5_GLUE3(H5T_NATIVE_, DTYPE, _NEG_INF_g); \ - else \ - *(D) = (DT)(*(S)); \ + else { \ + intmax_t s_cast = (intmax_t)(*(S)); \ + intmax_t d_cast = (intmax_t)(D_MAX); \ + \ + /* Check if source value would underflow destination. Do NOT do this \ + * by comparing against D_MIN casted to type ST here, as this will \ + * generally be undefined behavior (casting negative float value <= 1.0 \ + * to integer) for all floating point types and some compilers optimize \ + * this in a way that causes unexpected behavior. Instead, grab the \ + * absolute value of the source value first, then compare it to D_MAX. \ + */ \ + if (s_cast != INTMAX_MIN) \ + s_cast = imaxabs(s_cast); \ + else { \ + /* Handle two's complement integer representations where abs(INTMAX_MIN) \ + * can't be represented. Other representations will fall here as well, \ + * but this should be fine. \ + */ \ + s_cast = INTMAX_MAX; \ + d_cast -= 1; \ + } \ + \ + if (s_cast > d_cast) \ + *(D) = H5_GLUE3(H5T_NATIVE_, DTYPE, _NEG_INF_g); \ + else \ + *(D) = (DT)(*(S)); \ + } \ } #define H5T_CONV_Xf(STYPE, DTYPE, ST, DT, D_MIN, D_MAX) \ do { \ + HDcompile_assert(sizeof(ST) >= sizeof(DT)); \ H5T_CONV(H5T_CONV_Xf, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, Y) \ } while (0) @@ -9141,7 +9165,8 @@ H5T__conv_i_f(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts, siz goto padding; } } - else { + + if (!cb_struct.func || (except_ret == H5T_CONV_UNHANDLED)) { /*make destination infinity by setting exponent to maximal number and *mantissa to zero.*/ expo = expo_max; diff --git a/src/H5private.h b/src/H5private.h index 0cbda2e..e47dbb3 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -27,7 +27,6 @@ #include <errno.h> #include <fcntl.h> #include <fenv.h> -#include <math.h> #include <setjmp.h> #include <signal.h> #include <stdio.h> @@ -38,6 +37,7 @@ /* Define __STDC_WANT_IEC_60559_TYPES_EXT__ for _FloatN support, if available */ #define __STDC_WANT_IEC_60559_TYPES_EXT__ #include <float.h> +#include <math.h> /* POSIX headers */ #ifdef H5_HAVE_SYS_TIME_H @@ -462,10 +462,26 @@ #define H5_DBL_ABS_EQUAL(X, Y) (fabs((X) - (Y)) < DBL_EPSILON) #define H5_LDBL_ABS_EQUAL(X, Y) (fabsl((X) - (Y)) < LDBL_EPSILON) +#ifdef H5_HAVE__FLOAT16 +#ifdef H5_HAVE_FABSF16 +#define H5_FLT16_ABS_EQUAL(X, Y) (fabsf16((X) - (Y)) < FLT16_EPSILON) +#else +#define H5_FLT16_ABS_EQUAL(X, Y) H5_FLT_ABS_EQUAL((float)X, (float)Y) +#endif +#endif + #define H5_FLT_REL_EQUAL(X, Y, M) (fabsf(((Y) - (X)) / (X)) < (M)) #define H5_DBL_REL_EQUAL(X, Y, M) (fabs(((Y) - (X)) / (X)) < (M)) #define H5_LDBL_REL_EQUAL(X, Y, M) (fabsl(((Y) - (X)) / (X)) < (M)) +#ifdef H5_HAVE__FLOAT16 +#ifdef H5_HAVE_FABSF16 +#define H5_FLT16_REL_EQUAL(X, Y, M) (fabsf16(((Y) - (X)) / (X)) < (M)) +#else +#define H5_FLT16_REL_EQUAL(X, Y, M) H5_FLT_REL_EQUAL((float)X, (float)Y, M) +#endif +#endif + /* KiB, MiB, GiB, TiB, PiB, EiB - Used in profiling and timing code */ #define H5_KB (1024.0F) #define H5_MB (1024.0F * 1024.0F) @@ -543,16 +559,14 @@ #define H5_GCC_CLANG_DIAG_ON(x) #endif -/* Create a typedef for library usage of the _Float16 type - * to avoid issues when compiling the library with the - * -pedantic flag or similar where we get warnings about - * _Float16 not being an ISO C type. +/* If necessary, create a typedef for library usage of the + * _Float16 type to avoid issues when compiling the library + * with the -pedantic flag or similar where we get warnings + * about _Float16 not being an ISO C type. */ #ifdef H5_HAVE__FLOAT16 #if defined(__GNUC__) __extension__ typedef _Float16 H5__Float16; -#elif defined(__clang__) -/* TODO */ #else typedef _Float16 H5__Float16; #endif @@ -893,7 +907,7 @@ H5_DLL H5_ATTR_CONST int Nflock(int fd, int operation); #ifdef H5_HAVE_VASPRINTF #define HDvasprintf(RET, FMT, A) vasprintf(RET, FMT, A) #else -H5_DLL int HDvasprintf(char **bufp, const char *fmt, va_list _ap); +H5_DLL int HDvasprintf(char **bufp, const char *fmt, va_list _ap); #endif #endif |