]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix integer overflow in profile_count::probability_in
authorJan Hubicka <hubicka@ucw.cz>
Fri, 26 Sep 2025 10:39:07 +0000 (12:39 +0200)
committerJan Hubicka <hubicka@ucw.cz>
Fri, 26 Sep 2025 10:39:44 +0000 (12:39 +0200)
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.

gcc/profile-count.h

index 65c4596a2b0f50827680a6649d1f3d3f33f9a633..89746c6749fdf67b3b8d269ef49568dca1d3ea20 100644 (file)
@@ -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;