svl/source/numbers/zformat.cxx |   11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

New commits:
commit 6cb97ac7feee829b7ecd11ad2e76d4c846d40fd4
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:58 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/+/198290
    Reviewed-by: Xisco Fauli <[email protected]>

diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx
index 256f44cf8918..93c8955911e9 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

Reply via email to