
Daniel Veillard wrote: ...
However, the point is still valid, so I'll wait for confirmation. This is still about defensive coding, i.e., ensuring that maintenance doesn't violate invariants in harder-to-diagnose ways. If you get a bug report, which would you rather hear? "libvirt sometimes segfaults" or "I get an assertion failure on file.c:999"
I guess it's mostly a matter of coding style, I'm not sure it makes such a difference in practice, libvirt output will likely be burried in a log file, unless virsh or similar CLI tool is used. We have only 4 asserts in the code currently, I think it shows that so far we are not relying on it. On one hand this mean calling exit()
Is "don't use assert" libvirt policy? I hope not.
and I prefer a good old core dump for debugging than a one line message,
Same here, but there are many reasons for which a reporter will be unwilling or unable to provide a core dump. No one hesitates to include the output of a failed assertion in a bug report.
on the other hand if you managed to catch that message, well this can help pinpoint if the person reporting has no debugging skills.
I think there is pros and cons and that the current status quo is that we don't use asserts but more defensing coding by erroring out when this happen. The best way is not to assert() when we may dereference a NULL pointer but check for NULL at the point where we get that pointer, that's closer to the current code practice of libvirt (or well I expect so :-) and allow useful reporting (we failed to do a given operation) and a graceful error handling without exit'ing. So in general if we think we need an assert somewhere that mean that we failed to do the check at the right place, and I would
No. That is not how one should use assert, and certainly not how I proposed to use it. This is not about testing for a user- or system-provokable condition, but rather about testing code invariants. See below.
rather not start to get into the practice of just asserting in a zillion place instead of checking at the correct place.
So in my opinion, I'm still not fond of assert(), and I would prefer to catch up problem earlier, like parameter checking on function entry points or checking return value for functions producing pointers.
In that case, res being NULL means that both answer and request parameters are null after the retry: label, since the two pointers are not modified in the function this should be tested when entering the function,
if ((answer == NULL) && (request == NULL)) { virProxyError (NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); return -1; }
you get the error location, as in the assert but propagate the error back in the stack cleanly instead of exit'ing
It is important to distinguish two types of errors: - conditions that may arise due to user input or environment (misbehaving client or server, malformed packet, I/O error, etc.) - internal API abuse, violation of an internal assumption or invariant Using "assert" is appropriate only in the latter case, for detecting conditions that typically are provoked only by developer-introduced errors. Adding error-handling code like the above is appropriate only in the first case. Somewhat along these lines, we are starting to remove certain types of tests, (e.g., conn == NULL), when "conn" is always non-NULL. In the case of this patch, "request" is always non-null, and should probably have the "nonnull" attribute. New patch appended below. One advantage of using assert is that it usually _reduces_ the maintenance burden (i.e., when skimming the code, you may ignore the assert statement). However, if you add expressions like the above to "ensure" a condition that will always be true (i.e., that should not be possible to trigger via user input), you *increase* the maintenance burden by adding a test of an always-false condition that is handled as if it *can* sometimes be true. That would increase the WTF/m rate for certain readers. (http://www.osnews.com/story/19266/WTFs_m) Such a test might even trigger new warnings from tools like clang and coverity. Whether we use an assertion in this particular case is not important, but I hope that libvirt adopts a judicious policy on the use of "assert". Here's the revised patch, followed by the tiny nonnull-one. (also fixes typos s/ret/res/ in log message)
From 2a7fed9238667ff75a6ecd662b663549bc8fb7b5 Mon Sep 17 00:00:00 2001 From: Jim Meyering <meyering@redhat.com> Date: Wed, 6 Jan 2010 12:45:07 +0100 Subject: [PATCH] don't test "res == NULL" after we've already dereferenced "res"
* src/xen/proxy_internal.c (xenProxyCommand): "res" is known to be non-NULL at that point, so remove the "res == NULL" guard. --- src/xen/proxy_internal.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xen/proxy_internal.c b/src/xen/proxy_internal.c index ec4522b..ee4678a 100644 --- a/src/xen/proxy_internal.c +++ b/src/xen/proxy_internal.c @@ -1,7 +1,7 @@ /* * proxy_client.c: client side of the communication with the libvirt proxy. * - * Copyright (C) 2006, 2008, 2009 Red Hat, Inc. + * Copyright (C) 2006, 2008, 2009, 2010 Red Hat, Inc. * * See COPYING.LIB for the License of this software * @@ -444,7 +444,7 @@ retry: /* * do more checks on the incoming packet. */ - if ((res == NULL) || (res->version != PROXY_PROTO_VERSION) || + if ((res->version != PROXY_PROTO_VERSION) || (res->len < sizeof(virProxyPacket))) { virProxyError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("Communication error with proxy: malformed packet\n")); -- 1.6.6.425.g4dc2d
From eb6f7f0478ce510de8dc5fc9add4eaaca1c2bfc1 Mon Sep 17 00:00:00 2001 From: Jim Meyering <meyering@redhat.com> Date: Thu, 7 Jan 2010 19:48:05 +0100 Subject: [PATCH] proxy_internal.c: mark "request" parameter as nonnull
* src/xen/proxy_internal.c (xenProxyCommand): Mark "request" as an always-non-NULL parameter. --- src/xen/proxy_internal.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/xen/proxy_internal.c b/src/xen/proxy_internal.c index ee4678a..73a0469 100644 --- a/src/xen/proxy_internal.c +++ b/src/xen/proxy_internal.c @@ -340,7 +340,7 @@ xenProxyClose(virConnectPtr conn) return 0; } -static int +static int ATTRIBUTE_NONNULL(2) xenProxyCommand(virConnectPtr conn, virProxyPacketPtr request, virProxyFullPacketPtr answer, int quiet) { static int serial = 0; -- 1.6.6.425.g4dc2d