]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: intops: fix mul32hi()'s off-by-one
authorWilly Tarreau <w@1wt.eu>
Tue, 9 Feb 2021 16:10:54 +0000 (17:10 +0100)
committerWilly Tarreau <w@1wt.eu>
Tue, 9 Feb 2021 16:52:50 +0000 (17:52 +0100)
mul32hi() multiples a constant a with a variable b from 0 to 0xffffffff
and shifts the result by 32 bits. It's visible that it's always impossible
to reach the constant a this way because the product always misses exactly
one unit of a to be preserved. And this cannot be corrected by the caller
either as adding one to the output will only shift the output range, and
it's not possible to pass 2^32 on the ratio <b>. The right approach is to
add "a" after the multiplication so that the input range is always
preserved for all ratio values from 0 to 0xffffffff:

     (a=0x00000000 * b=0x00000000 + a=0x00000000) >> 32 = 0x00000000
     (a=0x00000000 * b=0x00000001 + a=0x00000000) >> 32 = 0x00000000
     (a=0x00000000 * b=0xffffffff + a=0x00000000) >> 32 = 0x00000000
     (a=0x00000001 * b=0x00000000 + a=0x00000001) >> 32 = 0x00000000
     (a=0x00000001 * b=0x00000001 + a=0x00000001) >> 32 = 0x00000000
     (a=0x00000001 * b=0xffffffff + a=0x00000001) >> 32 = 0x00000001
     (a=0xffffffff * b=0x00000000 + a=0xffffffff) >> 32 = 0x00000000
     (a=0xffffffff * b=0x00000001 + a=0xffffffff) >> 32 = 0x00000001
     (a=0xffffffff * b=0xffffffff + a=0xffffffff) >> 32 = 0xffffffff

This is only used in freq_ctr calculations and the slightly lower value
is unlikely to have ever been noticed by anyone. This may be backported
though it is not important.

include/haproxy/intops.h

index e5d795e63e93a4f35befb4e63d61a3b72aadba9a..a812874e5c30cea8b6c3ca66226e8193cf72e17a 100644 (file)
@@ -55,7 +55,7 @@ void mask_prep_rank_map(unsigned long m,
  */
 static inline unsigned int mul32hi(unsigned int a, unsigned int b)
 {
-       return ((unsigned long long)a * b) >> 32;
+       return ((unsigned long long)a * b + a) >> 32;
 }
 
 /* gcc does not know when it can safely divide 64 bits by 32 bits. Use this