taskset: fix non-fancy cpuset printing on big-endian

The non-fancy version of the from_cpuset uses CPU_SETSIZE as if it
represents the number of bytes in the cpuset, while it is actually
the number of bits. This leads to out-of-bounds accesses on the
cpu_set_t in the big-endian case. Basically all uses of CPU_SETSIZE
have to be divided by 8. This is done correctly in the fancy version
of from_cpuset.

In addition, the big-endian case is completely wrong to begin with.
All standard C libraries that I know of implement cpu_set_t as an
unsigned long array, so both for big and little endian, the least
significant bits are in the beginning of the array. Therefore, the
approach taken for the little endian case is equally valid. We only
need special handling for big endian when CPU_SETSIZE is large and
we use an unsigned long long to get more bits out.

Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
pull/1/head
Arnout Vandecappelle (Essensium/Mind) 2016-02-14 19:04:09 +01:00 committed by Denys Vlasenko
parent 03718bb274
commit 5fa9fefddc
1 changed files with 18 additions and 19 deletions

View File

@ -75,27 +75,26 @@ static char *from_cpuset(cpu_set_t *mask)
#define TASKSET_PRINTF_MASK "%llx" #define TASKSET_PRINTF_MASK "%llx"
static unsigned long long from_cpuset(cpu_set_t *mask) static unsigned long long from_cpuset(cpu_set_t *mask)
{ {
char *p = (void*)mask; BUILD_BUG_ON(CPU_SETSIZE < 8*sizeof(int));
BUILD_BUG_ON(CPU_SETSIZE < sizeof(int)); /* Take the least significant bits. Assume cpu_set_t is
* implemented as an array of unsigned long or unsigned
/* Take the least significant bits. Careful! * int.
* Consider both CPU_SETSIZE=4 and CPU_SETSIZE=1024 cases
*/ */
#if BB_BIG_ENDIAN if (CPU_SETSIZE < 8*sizeof(long))
/* For big endian, it means LAST bits */ return *(unsigned*)mask;
if (CPU_SETSIZE < sizeof(long)) if (CPU_SETSIZE < 8*sizeof(long long))
p += CPU_SETSIZE - sizeof(int); return *(unsigned long*)mask;
else if (CPU_SETSIZE < sizeof(long long)) # if BB_BIG_ENDIAN
p += CPU_SETSIZE - sizeof(long); if (sizeof(long long) > sizeof(long)) {
else /* We can put two long in the long long, but they have to
p += CPU_SETSIZE - sizeof(long long); * be swapped: the least significant word comes first in the
#endif * array */
if (CPU_SETSIZE < sizeof(long)) unsigned long *p = (void*)mask;
return *(unsigned*)p; return p[0] + ((unsigned long long)p[1] << (8*sizeof(long)));
if (CPU_SETSIZE < sizeof(long long)) }
return *(unsigned long*)p; # endif
return *(unsigned long long*)p; return *(unsigned long long*)mask;
} }
#endif #endif