On Fri, Aug 25, 2017 at 07:43:44AM -0400, John Ferlan wrote:
On 08/25/2017 02:19 AM, Martin Kletzander wrote:
> On Wed, Aug 23, 2017 at 12:56:02PM -0400, John Ferlan wrote:
>>
>>
>> On 08/21/2017 03:47 AM, Martin Kletzander wrote:
>>> There are many places in the code where virBufferCheckError() is used
>>> and then, right after that, virBufferContentAndReset() is called. The
>>> former has ATTRIBUTE_RETURN_CHECK, so every occurrence just checks
>>> that. However, if the return value of the latter is also the return
>>> value of the current function, there is no need to duplicate the work
>>> and act upon the error twice.
>>
>> If code doesn't really care or need to check the error, then it's
>> unnecessary...
>>
>>>
>>> This series proposes the idea of virCheckError being used for only
>>> reporting the error [1/4] and shows an example commit on how to clean
>>> up existing functions [2/4] so that it can be posted to our wiki under
>>>
https://wiki.libvirt.org/page/BiteSizedTasks and linked from there.>
>>> Further enhancements could go a step further and create one function
>>> (actually a macro the same way CheckError is done) and wrap those two
>>> lines in one so that it is even shorter. This, however, is not meant
>>> to be part of this series.
>>>
>>> Patches [3/4] and [4/4] utilize this for miscellaneous clean-ups in
>>> src/conf/.
>>>
>>>
>>> Martin Kletzander (4):
>>> util: Umark virBufferCheckErrorInternal as ATTRIBUTE_RETURN_CHECK
>>
>> Consider $subj as:
>>
>> util: Remove ATTRIBUTE_RETURN_CHECK from virBufferCheckErrorInternal
>>
>> but see my Coverity note below first...
>>
>>> util: Use virBufferCheckError to its full potential.
>>> conf: Clean up and report error in virDomainCapsFormat
>>> conf: Clean up and report error in virDomainGenerateMachineName
>>>
>>> src/conf/domain_capabilities.c | 68
>>> +++++++++++++++++-------------------------
>>> src/conf/domain_conf.c | 16 +++++-----
>>> src/util/virbitmap.c | 6 +---
>>> src/util/virbuffer.h | 2 +-
>>> 4 files changed, 37 insertions(+), 55 deletions(-)
>>>
>>> --
>>> 2.14.1
>>>
>>> --
>>> libvir-list mailing list
>>> libvir-list(a)redhat.com
>>>
https://www.redhat.com/mailman/listinfo/libvir-list
>>>
>>
>> While what you have works just fine - it causes new Coverity warnings
>> regarding the fact that 209 of 212 places check for error, but the 3 new
>> callers don't.
>>
>
> I don't really understand this warning. If we have, let's say, 300
> callers of memmove() and 290 of them use the return value, but 10 of
> them don't, then it will issue a warning as well?
>
I don't know exactly how Coverity counts and keeps track because there
are some that don't show up at all and then one day someone pushes a
change and a warning is issue that N of M check status where M is not
necessarily N+1. Sometimes it's N+5 or N+8. It seems as though there's
heuristics that know when we go from 100% checking status to some value
less as much as it knows that there were (for example) 90% of the calls
checking and some change pushed that to 95% and now flags those other
5%. That to me is the oddest of the cases, but is one I've seen happen.
That is someone made a change to foo.c and then Coverity messages on
bar.c that's using the same function without checks.
So that all says to me perhaps it's a false positive type message and it
can always be ignored; however, that isn't always the case. So, I think
the purpose of the message is to ensure that the places that are (now)
failing the test are checked to ensure nothing's being missed such as no
status check on some function that ends up allocating memory. The goal
being to cause the user of coverity to check just in case.
Oh, interesting to know. I kind of get the reasoning behind
this... Kind of.
>> As an alternative, why not add and use:
>>
>> /**
>> * virBufferReportError
>> *
>> * Similar to above, but wraps inside an ignore_value for paths that
>> * don't need to check the return status.
>> */
>> # define virBufferReportError(buf) \
>> ignore_value(virBufferCheckErrorInternal(buf, VIR_FROM_THIS, \
>> __FILE__, __FUNCTION__, __LINE__))
>>
>> Instead of dropping the ATTRIBUTE_RETURN_CHECK
>>
>
> I don't like the fact that it's workaround. It's like having a function
> that does four things at once and you call it and then revert two of
> those things =D
>
Well if the "long term plan" is to make return value checking
unnecessary for some virBufferCheckErrorInternal, then there's a couple
of options. I presented one alternative which seemed simple enough.
I know altering changes for what is perceived as a false positive in
coverity is not generally a desired option, so I'm fine with the code as
is since when this human reads the code he can easily determine the
virBufferCheckErrorInternal doesn't need to have it's return value
checked since virBufferContentAndReset will handle the error properly.
Your cover letter indicated future enhancements in order to cover some
of the other cases which is what got me thinking perhaps this could
change so that we don't end up with those future enhancements running
into the same issue (assuming anyone picks up the task).
So, if I didn't mention that it was coverity complaining and instead
said - why not take the plunge now and create a void function that does
the same thing as the int function, would that have made a difference?
I'd rather see a #define wrapper that allows one to ignore the status
because they don't care. That leaves it to the caller to decide whether
or not to check the returned status. I just chose to explain why.
Sure, I'm generally fine with both, I just think one of them is cleaner.
>> IDC either way - less places for me to add ignore_value()
wrapper ;-)
>>
>> Whichever way you decide is fine by me though, so
>>
>
> Even if it generates coverity warnings? I mean they are sometimes good
> and can mean something (unless it's a thing that it cannot deduct from
> the code, of course), but I don't understand this one. If it adds ne
> warnings, I'll go with your version, but I would rather understand it
> first.
>
It won't be the first time... I've given up on others - I just add them
to my local branch. For example, qemuBuildShmemBackendMemProps calls
virJSONValueObjectCreate which in all other cases expects status return
check; however, for this function it doesn't make sense since the caller
would be checking the returned @ret anyway. Still Coverity complains, so
in order to avoid that I wrapped the call in ignore_value. If someone
makes change to the same place my branch has a merge conflict which I
have to resolve. There's similar type workarounds in my local branch for
qemuMigrationCookieStatisticsXMLParse and the *last* call to virXPathInt
as well as qemuCgroupEmulatorAllNodesRestore and the call to
virCgroupSetCpusetMems.
I currently have 30 patches of varying degrees of false positives.
Things that have been NACK'd in upstream reviews as a waste of a patch
to work around what some consider a defect in the analyzer. I have a
fair number of /* coverity[leaked_storage] */ because functions like
virJSONValueObjectCreate will "consume" the address of something via the
"a:XXXX" argument, but coverity cannot determine that so it just
elicits the warning to ensure the consumer checks to be sure.
I get your point, on the other hand I must say I agree with the reviews
most of the time. But please don't waste time on the patches. They
will only accumulate and eat up more and more of your time during
rebases. I'm sure the conflicts are fine, but still... My feeling is
that adding workarounds for coverity are sometimes fine (coverity can
find interesting stuff), but whenever it hinders the code readability it
inherently makes people do more mistakes.
I'm really sorry for this, but I really don't see the point, in this
particular case, for making coverity happy. I'll go with my approach,
but I promise you I'll be telling newbies about this task in particular.
Thanks for the review and thorough explanation of the process.
Martin