[libvirt] [PATCH] util: Fix coverity warings in virProcessGetAffinity
John Ferlan
jferlan at redhat.com
Wed Jun 10 15:27:14 UTC 2015
On 06/10/2015 09:41 AM, Peter Krempa wrote:
> On Thu, Jun 04, 2015 at 08:34:00 -0400, John Ferlan wrote:
>> On 06/04/2015 08:15 AM, Peter Krempa wrote:
>>> Refactor the code flow a bit more to clear coverity errors.
>>>
>>> Store the cpu count in an intermediate variable and reuse it rather than
>>> caluclating the index.
>>> ---
>>> src/util/virprocess.c | 11 +++++++----
>>> 1 file changed, 7 insertions(+), 4 deletions(-)
>>>
>
> ...
>
>>
>> ^^^ Coverity still complains here
>>
>> No real change since previous...
>>
nice detective work...
>
> So I went in and traced it a bit. cpu_set_t is basically the following
> structure: (assuming sizeof(unsigned long int) == 8))
>
> typedef struct
> {
> unsigned long int __bits[1024 / 8 * 8];
> } cpu_set_t;
>
>
> The CPU_ALLOC() macro allocates an array of such structures. Since the
> size of the __bits array is rounded nicely (128 bytes) the structure
> itself does not add any padding and it's size is 128 bytes too the
> structures are packed and thus the __bits fields of adjecent structures
> basically form a longer array of unsigned long ints.
>
> The CPU_ISSET_S macro then translates basically to this equivalent
> function:
>
> unsigned long int
> CPU_ISSET_S(size_t __cpu,
> size_t setsize,
> cpu_set_t *cpusetp)
> {
> if (__cpu / 8 < setsize) {
> unsigned long int subcpu = ((const unsigned long int *)(mask->__bits))[__cpu / 64];
> unsigned long int mask = (unsigned long int) 1 << (__cpu % 64);
>
> return subcpu & mask;
> } else {
> return 0;
> }
> }
>
> The macro expects that the array is packed nicely and treats it
> basically as a large array of unsigned ints. The macro then selects one
> of the members and masks out the required cpu bit.
>
> So then compiling the following proof of concept:
>
> #define _GNU_SOURCE
> #include <sched.h>
>
> int main(void)
> {
> size_t ncpus = 1024 << 8;
> size_t masklen = CPU_ALLOC_SIZE(ncpus);
> cpu_set_t *mask = CPU_ALLOC(ncpus);
>
> CPU_ZERO_S(masklen, mask);
>
> for (size_t i = 0; i < ncpus; i++) {
> if (CPU_ISSET_S(i, masklen, mask)) {
> i = i;
> }
> }
> CPU_FREE(mask);
>
> return 0;
> }
>
> And running it in valgrind results in no error as expected:
>
> $ valgrind ./a.out
> ==95609== Memcheck, a memory error detector
> ==95609== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
> ==95609== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
> ==95609== Command: ./a.out
> ==95609==
> ==95609==
> ==95609== HEAP SUMMARY:
> ==95609== in use at exit: 0 bytes in 0 blocks
> ==95609== total heap usage: 1 allocs, 1 frees, 32,768 bytes allocated
> ==95609==
> ==95609== All heap blocks were freed -- no leaks are possible
> ==95609==
> ==95609== For counts of detected and suppressed errors, rerun with: -v
> ==95609== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
>
> The problem is that coverity thinks that the code overruns the __bits
> array now that the code is simple enough to introspect which is
> technically true. Previously the same situation would happen but the
> loop that would resize the array incrementally probably was not
> introspected properly and thus did not produce a warning.
>
> So there are basically three options:
> 1) Silence the coverity warning
So on line just prior to CPU_ISSET_S either:
sa_assert(sizeof(unsigned long int) == sizeof(cpu_set_t));
or
/* coverity[overrun-local] */
Silences the warning
ACK for the current adjustment - your call if you want the sa_assert or
the coverity noise.
John
> 2) File a bug against libc or something to fix the macro
> 3) Reimplement CPU_ISSET_S internally. (Which I don't think will be
> possible since cpu_set_t does not look public)
>
> At any rate, there is no problem in libvirt's usage as it conforms to
> the example in the man page.
>
> As of this particular patch. It does not fix the coverity warning, but I
> think the intention and code flow is more apparent once it's applied.
>
More information about the libvir-list
mailing list