Re: [PATCH] sched/fair: Use 'unsigned long' for group_shares,group_runnable

From: chengjian (D)
Date: Mon Apr 15 2019 - 11:20:53 EST


Hi, Peter


On 2019/4/15 20:46, Peter Zijlstra wrote:

I write a demo about this, which I described it as overflow.

#cat test.c

//test.c
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>

int main(void)
{
ÂÂÂ long a = 1048576 * 9144968455305; /* shares = tg_shares * load */
ÂÂÂ unsigned long b = a;
ÂÂÂ //unsigned long e = 1048576 * 9144968455305;

ÂÂÂ printf("LONG_MAX = %ld, 0x%lx\n", LONG_MAX, LONG_MAX);
ÂÂÂ printf("ULONG_MAX = %lu, 0x%lx\n", ULONG_MAX, ULONG_MAX);

ÂÂÂ if (b > LONG_MAX)
ÂÂÂ ÂÂÂ printf("==overflow!!!==\n");ÂÂ // OVERFLOW
ÂÂÂ printf("a = %20ld,0x%016lx\n", a, a);
ÂÂÂ printf("b = %20lu,0x%016lx\n", b, b);

ÂÂÂ /* shares /= tg_weight */
ÂÂÂ printf("a/3 = 0x%016lx\n", (a / 3)); ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ // WRONG
ÂÂÂ printf("a/3 = 0x%016lx\n", (((unsigned long)a) / 3));ÂÂ // unsigned
ÂÂÂ printf("a/3 = 0x%016lx\n", (a / (unsigned long)3));ÂÂÂ // unsigned
ÂÂÂ printf("b/3 = 0x%016lx\n", b / 3);ÂÂÂ ÂÂÂ ÂÂÂ // unsigned

ÂÂÂ return EXIT_SUCCESS;
}



#./test

LONG_MAX = 9223372036854775807, 0x7fffffffffffffff
ULONG_MAX = 18446744073709551615, 0xffffffffffffffff
==overflow!!!==
a = -8857549630719655936,0x8513a98a48900000
b =Â 9589194442989895680,0x8513a98a48900000
a/3 = 0xd7068dd8c2daaaabÂÂÂÂ //Â WRONG
a/3 = 0x2c5be32e18300000
a/3 = 0x2c5be32e18300000
b/3 = 0x2c5be32e18300000



On Sat, Apr 13, 2019 at 03:32:34AM +0000, Cheng Jian wrote:
group_share and group_runnable are tracked as 'unsigned long',
however some functions using them as 'long' which is ultimately
assigned back to 'unsigned long' variables in reweight_entity.

Since there is not scope on using a different and signed type,
this change improves code consistency and avoids further type
conversions. More important, to prevent undefined behavior
caused by overflow.
There is no undefined behaviour due to overflow.UBSAN is broken,
upgrade to GCC8 or later.

.


So, function calc_group_shares will return the wrong value.


```cpp

static long calc_group_shares(struct cfs_rq *cfs_rq)
{

ÂÂÂ // ......

ÂÂÂ shares = (tg_shares * load);
ÂÂÂ if (tg_weight)
ÂÂÂ ÂÂÂ shares /= tg_weight;
}

```


The same to calc_group_runnable.


Thanks.

ÂÂÂ CHENG Jian.