From 1f5d14df4d93189a32e4cd2221ab0461cb1a0a31 Mon Sep 17 00:00:00 2001 From: Andrew Dutcher Date: Sat, 20 Aug 2016 04:30:57 -0700 Subject: [PATCH] Port patch from upstream to check for invalid long double encodings --- qemu/fpu/softfloat.c | 118 ++++++++++++++++++++++++++++++----- qemu/include/fpu/softfloat.h | 15 +++++ 2 files changed, 116 insertions(+), 17 deletions(-) diff --git a/qemu/fpu/softfloat.c b/qemu/fpu/softfloat.c index 16b21ebe..81c8f3d6 100644 --- a/qemu/fpu/softfloat.c +++ b/qemu/fpu/softfloat.c @@ -4602,6 +4602,10 @@ int32 floatx80_to_int32( floatx80 a STATUS_PARAM ) int32 aExp, shiftCount; uint64_t aSig; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return 1 << 31; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -4630,6 +4634,10 @@ int32 floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM ) uint64_t aSig, savedASig; int32_t z; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return 1 << 31; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -4674,6 +4682,10 @@ int64 floatx80_to_int64( floatx80 a STATUS_PARAM ) int32 aExp, shiftCount; uint64_t aSig, aSigExtra; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return (uint64_t)1 << 63; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -4715,6 +4727,10 @@ int64 floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM ) uint64_t aSig; int64 z; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return (uint64_t)1 << 63; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -4755,6 +4771,10 @@ float32 floatx80_to_float32( floatx80 a STATUS_PARAM ) int32 aExp; uint64_t aSig; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return float32_default_nan; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -4783,6 +4803,10 @@ float64 floatx80_to_float64( floatx80 a STATUS_PARAM ) int32 aExp; uint64_t aSig, zSig; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return float64_default_nan; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -4811,6 +4835,10 @@ float128 floatx80_to_float128( floatx80 a STATUS_PARAM ) int_fast16_t aExp; uint64_t aSig, zSig0, zSig1; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return float128_default_nan; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -4836,6 +4864,10 @@ floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM ) uint64_t lastBitMask, roundBitsMask; floatx80 z; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return floatx80_default_nan; + } aExp = extractFloatx80Exp( a ); if ( 0x403E <= aExp ) { if ( ( aExp == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) { @@ -5058,6 +5090,10 @@ floatx80 floatx80_add( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid STATUS_VAR); + return floatx80_default_nan; + } aSign = extractFloatx80Sign( a ); bSign = extractFloatx80Sign( b ); if ( aSign == bSign ) { @@ -5079,6 +5115,10 @@ floatx80 floatx80_sub( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid STATUS_VAR); + return floatx80_default_nan; + } aSign = extractFloatx80Sign( a ); bSign = extractFloatx80Sign( b ); if ( aSign == bSign ) { @@ -5103,6 +5143,10 @@ floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM ) uint64_t aSig, bSig, zSig0, zSig1; floatx80 z; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid STATUS_VAR); + return floatx80_default_nan; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -5163,6 +5207,10 @@ floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM ) uint64_t rem0, rem1, rem2, term0, term1, term2; floatx80 z; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid STATUS_VAR); + return floatx80_default_nan; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -5243,6 +5291,10 @@ floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM ) uint64_t q, term0, term1, alternateASig0, alternateASig1; floatx80 z; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid STATUS_VAR); + return floatx80_default_nan; + } aSig0 = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -5339,6 +5391,10 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3; floatx80 z; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return floatx80_default_nan; + } aSig0 = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); @@ -5405,10 +5461,11 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) { - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) + || (extractFloatx80Exp(a) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(a) << 1)) + || (extractFloatx80Exp(b) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(b) << 1)) ) { float_raise( float_flag_invalid STATUS_VAR); return 0; @@ -5434,10 +5491,11 @@ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) + || (extractFloatx80Exp(a) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(a) << 1)) + || (extractFloatx80Exp(b) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(b) << 1)) ) { float_raise( float_flag_invalid STATUS_VAR); return 0; @@ -5467,10 +5525,11 @@ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) + || (extractFloatx80Exp(a) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(a) << 1)) + || (extractFloatx80Exp(b) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(b) << 1)) ) { float_raise( float_flag_invalid STATUS_VAR); return 0; @@ -5497,10 +5556,11 @@ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) *----------------------------------------------------------------------------*/ int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM ) { - if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) - || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b) + || (extractFloatx80Exp(a) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(a) << 1)) + || (extractFloatx80Exp(b) == 0x7FFF + && (uint64_t) (extractFloatx80Frac(b) << 1)) ) { float_raise( float_flag_invalid STATUS_VAR); return 1; @@ -5518,6 +5578,10 @@ int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM ) int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid STATUS_VAR); + return 0; + } if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) @@ -5549,6 +5613,10 @@ int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid STATUS_VAR); + return 0; + } if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) @@ -5585,6 +5653,10 @@ int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid STATUS_VAR); + return 0; + } if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) @@ -5618,6 +5690,10 @@ int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) *----------------------------------------------------------------------------*/ int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid STATUS_VAR); + return 1; + } if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) @@ -6855,7 +6931,7 @@ uint32 float32_to_uint32( float32 a STATUS_PARAM ) } else { return v; } - set_float_exception_flags(old_exc_flags, status); + set_float_exception_flags(old_exc_flags STATUS_VAR); float_raise(float_flag_invalid STATUS_VAR); return res; } @@ -7145,6 +7221,10 @@ static inline int floatx80_compare_internal( floatx80 a, floatx80 b, { flag aSign, bSign; + if (floatx80_invalid_encoding(a) || floatx80_invalid_encoding(b)) { + float_raise(float_flag_invalid STATUS_VAR); + return float_relation_unordered; + } if (( ( extractFloatx80Exp( a ) == 0x7fff ) && ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7fff ) && @@ -7409,6 +7489,10 @@ floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) int32_t aExp; uint64_t aSig; + if (floatx80_invalid_encoding(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return floatx80_default_nan; + } aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); diff --git a/qemu/include/fpu/softfloat.h b/qemu/include/fpu/softfloat.h index e32e25d5..8dc81c2f 100644 --- a/qemu/include/fpu/softfloat.h +++ b/qemu/include/fpu/softfloat.h @@ -625,6 +625,21 @@ static inline int floatx80_is_any_nan(floatx80 a) return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1); } +/*---------------------------------------------------------------------------- +| Return whether the given value is an invalid floatx80 encoding. +| Invalid floatx80 encodings arise when the integer bit is not set, but +| the exponent is not zero. The only times the integer bit is permitted to +| be zero is in subnormal numbers and the value zero. +| This includes what the Intel software developer's manual calls pseudo-NaNs, +| pseudo-infinities and un-normal numbers. It does not include +| pseudo-denormals, which must still be correctly handled as inputs even +| if they are never generated as outputs. +*----------------------------------------------------------------------------*/ +static inline bool floatx80_invalid_encoding(floatx80 a) +{ + return (a.low & ((uint64_t)1 << 63)) == 0 && (a.high & 0x7FFF) != 0; +} + #define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL) #define floatx80_one make_floatx80(0x3fff, 0x8000000000000000LL) #define floatx80_ln2 make_floatx80(0x3ffe, 0xb17217f7d1cf79acLL)