svl/source/numbers/zformat.cxx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-)
New commits: commit 3d3b372728640a57c4883ad814d608f2f7324573 Author: Stephan Bergmann <[email protected]> AuthorDate: Wed Jan 28 09:48:25 2026 +0100 Commit: Xisco Fauli <[email protected]> CommitDate: Wed Jan 28 16:08:54 2026 +0100 Avoid float-cast-overflow ...by completely getting rid of the code exhibiting UB and the helpless workaround from 2b27652d2d7bd675fa355fb904755bf5fb312348 "tdf#167892 fix hang formatting very small number on windows". TODO: It is unclear to me whether using saturated values here is any better than using whatever random values came out of the original code that exhibited UB. The whole algorithm probably needs to be replaced with something that actually works. (This was now reported with 4368272648f7264d4a2884db80bf5a100ab9d8ca "tdf#167892: svl_qa_cppunit: Add test" as > /svl/source/numbers/zformat.cxx:2886:52: runtime error: 1e+19 is outside the range of representable values of type 'long' > #0 0x7f3f6da013eb in SvNumberformat::ImpGetFractionElements(double&, unsigned short, double&, long&, long&) const /svl/source/numbers/zformat.cxx:2886:52 > #1 0x7f3f6d9f84ee in SvNumberformat::ImpGetFractionOutput(double, unsigned short, bool, NativeNumberWrapper const&, rtl::OUStringBuffer&) const /svl/source/numbers/zformat.cxx:2961:5 > #2 0x7f3f6d9e472a in SvNumberformat::GetOutputString(double, rtl::OUString&, Color const**, NativeNumberWrapper const&, SvNFLanguageData const&, bool) const /svl/source/numbers/zformat.cxx:2676:21 > #3 0x7f3f6d8c37bc in SvNFEngine::GetPreviewString(SvNFLanguageData&, SvNFFormatData const&, NativeNumberWrapper const&, SvNFEngine::Accessor const&, rtl::OUString const&, double, rtl::OUString&, Color const**, o3tl::strong_int<unsigned short, LanguageTypeTag>, bool) /svl/source/numbers/zforlist.cxx:2147:20 > #4 0x7f3f6d8c3ddb in SvNumberFormatter::GetPreviewString(rtl::OUString const&, double, rtl::OUString&, Color const**, o3tl::strong_int<unsigned short, LanguageTypeTag>, bool) /svl/source/numbers/zforlist.cxx:2165:12 > #5 0x7f3f6ef90fd3 in (anonymous namespace)::Test::checkPreviewString(SvNumberFormatter&, rtl::OUString const&, double, o3tl::strong_int<unsigned short, LanguageTypeTag>, rtl::OUString const&) /svl/qa/unit/svl.cxx:462:21 > #6 0x7f3f6ef67f13 in (anonymous namespace)::Test::testUserDefinedNumberFormats() /svl/qa/unit/svl.cxx:1443:9 <https://ci.libreoffice.org/job/lo_ubsan/3801/>.) Change-Id: Iff449629ee309f9513af02da9dfdf2505d6fe725 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198278 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <[email protected]> (cherry picked from commit aee7b9b8e08531ae01dd30f879c0c0872e60278d) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198289 Reviewed-by: Xisco Fauli <[email protected]> diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx index 0c33ade1f94c..89bd8eb9e56f 100644 --- a/svl/source/numbers/zformat.cxx +++ b/svl/source/numbers/zformat.cxx @@ -19,6 +19,7 @@ #include <string_view> +#include <o3tl/float_int_conversion.hxx> #include <o3tl/sprintf.hxx> #include <o3tl/string_view.hxx> #include <o3tl/numeric.hxx> @@ -2883,15 +2884,7 @@ void SvNumberformat::ImpGetFractionElements ( double& fNumber, sal_uInt16 nIx, while ( fRemainder > 0.0 ) { double fTemp = 1.0 / fRemainder; // 64bits precision required when fRemainder is very weak - nPartialDenom = static_cast<sal_Int64>(floor(fTemp)); // due to floating point notation with double precision - // The fTemp value may be out of range for sal_Int64 (e.g. 1e+19), and the result of - // casting that is undefined. In practice, gcc/llvm gives us a large positive number, - // but depending on the compiler, we have either a large positive number (which works fine) - // or a a large negative number, which will make this algorithm oscillate. - // So apply a correction that makes all the compilers work reasonbly. - // There is probably a better algorithm to be used here for this whole function. - if (nPartialDenom < 0) - nPartialDenom = -(nPartialDenom+1); + nPartialDenom = o3tl::saturating_cast<sal_Int64>(floor(fTemp)); // due to floating point notation with double precision fRemainder = fTemp - static_cast<double>(nPartialDenom); nDivNext = nPartialDenom * nDiv + nDivPrev; if (nDivNext <= nBasis) // continue loop
