[libvirt] [PATCH 2/5] commandtest: Resolve some coverity resource leaks
Peter Krempa
pkrempa at redhat.com
Fri Feb 15 09:01:38 UTC 2013
On 02/14/13 20:00, John Ferlan wrote:
> On 02/14/2013 12:43 PM, Eric Blake wrote:
>> On 02/14/2013 10:15 AM, Peter Krempa wrote:
>>> On 02/14/13 17:42, John Ferlan wrote:
>>>> ---
>>>> tests/commandtest.c | 17 ++++++++++++-----
>>>> 1 file changed, 12 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/tests/commandtest.c b/tests/commandtest.c
>>>> index 93c6333..3bfc358 100644
>>>> --- a/tests/commandtest.c
>>>> +++ b/tests/commandtest.c
>>>
>>> ...
>>>
>>>> @@ -963,16 +964,19 @@ mymain(void)
>>>> dup2(fd, 6) < 0 ||
>>>> dup2(fd, 7) < 0 ||
>>>> dup2(fd, 8) < 0 ||
>>>> - (fd > 8 && VIR_CLOSE(fd) < 0))
>>>> + (fd > 8 && VIR_CLOSE(fd) < 0)) {
>>>> + VIR_FORCE_CLOSE(fd);
>>>> return EXIT_FAILURE;
>>>> + }
>>>> + sa_assert(fd == -1);
>>>
>>> according to man of dup2():
>>> * If oldfd is a valid file descriptor, and newfd has the same value
>>> as oldfd, then dup2() does nothing, and returns newfd.
>>>
>>> It is possible that open returns fd < 8, dup2() on that does nothing and
>>> afterwards this assertion won't be true.
>>
>> I gave my ACK too soon - Peter is right that fd _might_ not be -1 at
>> this point. There are two cases to consider:
>>
>> 1. start life with fds 3-8 already opened by inheritance (rare). Opening
>> /dev/null gets fd 9, which we then dup to 3-8 (overwriting whatever was
>> inherited from the environment), then we close 9. If we fail to dup2,
>> we still close 9, but none of the other fds which we forcefully
>> overwrote. In this case, fd==-1 is true when you get to the sa_assert.
>>
>> 2. start life with at least one of fd 3-8 closed (most common). Opening
>> /dev/null then gets the first open fd, which we then dup to all the
>> remaining fds between 3-8. We don't close fd in this case, because we
>> want fds 3-8 opened on /dev/null; so in this case, fd==-1 is false.
>>
>> Does the assert actually fix anything? I think it is best to remove it.
>>
>
> Without the sa_assert, the following is coughed up by Coverity:
>
> 979
> 980 /* Phase two of killing interfering fds; see above. */
>
> (20) Event overwrite_var: Overwriting handle "fd" in "fd = 3" leaks the
> handle.
From a human point of view this is a false positive:
1) In case fd <= 8, it gets dup2()-ed to itself and we close it later.
2) In case fd > we close it anyway
But the analyzer has hard time following our manual closing of the
handles afterwards.
> Also see events:
> [open_fn][var_assign][noescape][noescape][noescape][noescape][noescape][noescape]
>
> 981 fd = 3;
> 982 VIR_FORCE_CLOSE(fd);
>
> When I first modified this code it was still fd 3->5 being dup2'd and
> the sa_assert() worked for at least shutting coverity up, but I see the
> point about the last if condition.
>
> So, one could logically believe the check could change to:
>
> sa_assert(fd == -1 || (fd >= 3 && fd <= 8));
Hm, I think I know why this shuts coverity up: the assertion statement
forces coverity to think that the last part of the if statement was true
and thus fd was explicitly closed.
In this case, I think it's okay to use it to shut coverity up as long as
"sa_assert" doesn't have any effect outside of static analysis.
We know that we're doing the right thing with the fds so no need for
coverity to whine about that.
I don't know if this is worth bothering any more and even filing a bug
against coverity. We're doing some pretty ugly stuff here from the POV
of static analysis.
>
> but that too triggers Coverity to complain that we're overwriting the
> fd. So without creating a new variable and adding more busy work, adding
> the following prior to the initialization removes the warning.
>
>
> /* coverity[overwrite_var] - silence the obvious */
> fd = 3;
>
>
> Also, yes, it's strange on the error case of the if condition that one
> doesn't have to do the same close 3->8 game even though the
> VIR_FORCE_CLOSE(fd) was needed.
>
>>>
>>>>
>>>> /* Prime the debug/verbose settings from the env vars,
>>>> * since we're about to reset 'environ' */
>>>> ignore_value(virTestGetDebug());
>>>> ignore_value(virTestGetVerbose());
>>>>
>>>> - if (virInitialize() < 0)
>>>> - return EXIT_FAILURE;
>>>> + /* Make sure to not leak fd's */
>>>> + virinitret = virInitialize();
>>>>
>>>> /* Phase two of killing interfering fds; see above. */
>>>> fd = 3;
>>>
>>> ACK with the assertion removed or a sufficient explanation provided.
I think this is a sufficient explanation, so ACK (as long as sa_assert
has no side effects normally).
>>>
>>> Peter
>>>
More information about the libvir-list
mailing list