https://gcc.gnu.org/g:9f9c8d63a5822378e18f3f8f188df21c6104e18e

commit r16-4103-g9f9c8d63a5822378e18f3f8f188df21c6104e18e
Author: Jan Hubicka <[email protected]>
Date:   Fri Sep 26 12:39:07 2025 +0200

    Fix integer overflow in profile_count::probability_in
    
    This patch fixes integer overflow in profile_count::probability_in which 
happens
    for very large counts.  This was probably not that common in practice until
    scaled AutoFDO profiles were intorduces.
    
    This was introduced as cut&paste from profile_probability implementation.
    I reviewed multiplicaitons in the file for safety and noticed that in some
    cases the code is over-protective. In profile_probability::operator/ we 
alrady
    scale that m_val <= other.m_val and thus we know result will be in the range
    0...max_probability.  In profile_probability::apply_scale we deal with 30bit
    value from profile_probability so no overflow can happen.
    
    gcc/ChangeLog:
    
            * profile-count.h (profile_probability::operator/): Do not cap
            twice.
            (profile_probability::operator/=): Likewise.
            (profile_probability::apply_scale): Do not watch for overflow.
            (profile_count::probability_in): Watch overflow.

Diff:
---
 gcc/profile-count.h | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/gcc/profile-count.h b/gcc/profile-count.h
index 65c4596a2b0f..89746c6749fd 100644
--- a/gcc/profile-count.h
+++ b/gcc/profile-count.h
@@ -450,9 +450,7 @@ public:
       else
        {
          gcc_checking_assert (other.m_val);
-         ret.m_val = MIN (RDIV ((uint64_t)m_val * max_probability,
-                                other.m_val),
-                          max_probability);
+         ret.m_val = RDIV ((uint64_t)m_val * max_probability, other.m_val);
        }
       ret.set_quality (MIN (MIN (quality (), other.quality ()), ADJUSTED));
       return ret;
@@ -480,9 +478,7 @@ public:
          else
            {
              gcc_checking_assert (other.m_val);
-             m_val = MIN (RDIV ((uint64_t)m_val * max_probability,
-                                other.m_val),
-                          max_probability);
+             m_val = RDIV ((uint64_t)m_val * max_probability, other.m_val);
            }
          set_quality (MIN (MIN (quality (), other.quality ()), ADJUSTED));
        }
@@ -576,9 +572,8 @@ public:
       gcc_checking_assert (den.m_val);
 
       profile_probability ret;
-      uint64_t val;
-      safe_scale_64bit (m_val, num.m_val, den.m_val, &val);
-      ret.m_val = MIN (val, max_probability);
+      ret.m_val = MIN (RDIV ((uint64_t)m_val * num.m_val, den.m_val),
+                      max_probability);
       ret.set_quality (MIN (MIN (MIN (quality (), ADJUSTED),
                            num.quality ()), den.quality ()));
       return ret;
@@ -1331,8 +1326,14 @@ public:
          return ret;
        }
       else
-       ret.m_val = RDIV (m_val * profile_probability::max_probability,
-                         overall.m_val);
+       {
+         gcc_checking_assert (overall.m_val);
+         uint64_t tmp;
+         safe_scale_64bit (m_val, profile_probability::max_probability,
+                           overall.m_val, &tmp);
+         gcc_checking_assert (tmp <= profile_probability::max_probability);
+         ret.m_val = tmp;
+       }
       ret.set_quality (MIN (MAX (MIN (m_quality, overall.m_quality),
                                 GUESSED), ADJUSTED));
       return ret;

Reply via email to