PG-350: Fix bucket time overflow.

To check if a bucket has expired, a comparison of the time elapsed
since last bucket change was being done in get_next_wbucket() function
using the following line:

while ((current_usec - current_bucket_usec) > (PGSM_BUCKET_TIME
* 1000 * 1000))

The problem is that the expression compares a uint64 (current_usec)
with a int32 (PGSM_BUCKET_TIME), if a given user configures a value for
pgsm_bucket_time GUC (let's call it T) that could overflow int32 range
in the expression T*1000*1000 > 2**31-1, then the result would be a
negative integer cast to (uint64), resulting in a large uint64 value that
would evaluate the expression as false, thus never updating bucket
number.

When querying pg_stat_monitor view, for every entry it's verified if
the entry has not yet expired by calling IsBucketValid(bucket_number).
Using the entry's bucket number the function calculates if the time
since the bucket started, using shared global variable
pgss->bucket_start_time[bucket_id], is still valid.

Since pgss->bucket_start_time is not properly initialized in
get_next_wbucket(), the function IsBucketValid() will always
return false, thus not listing any entries in the view.
pull/188/head
Diego Fronza 2022-02-21 11:19:05 -03:00 committed by Hamid Akhtar
parent 5528bef82d
commit d839cc4255
1 changed files with 1 additions and 1 deletions

View File

@ -2089,7 +2089,7 @@ get_next_wbucket(pgssSharedState *pgss)
* definitely make the while condition to fail, we can stop the loop as another * definitely make the while condition to fail, we can stop the loop as another
* thread has already updated prev_bucket_usec. * thread has already updated prev_bucket_usec.
*/ */
while ((current_usec - current_bucket_usec) > (PGSM_BUCKET_TIME * 1000 * 1000)) while ((current_usec - current_bucket_usec) > ((uint64)PGSM_BUCKET_TIME * 1000LU * 1000LU))
{ {
if (pg_atomic_compare_exchange_u64(&pgss->prev_bucket_usec, &current_bucket_usec, current_usec)) if (pg_atomic_compare_exchange_u64(&pgss->prev_bucket_usec, &current_bucket_usec, current_usec))
{ {