Am Freitag, 24. Februar 2012, 18:21:37 schrieb Guido Winkelmann:
Am Donnerstag, 23. Februar 2012, 13:40:03 I wrote:
> Am Mittwoch, 22. Februar 2012, 11:26:50 schrieb Eric Blake:
> > Can you post the code snippet you are using to get this situation?
>
> Unfortunately, the problem occurs inside a fairly large, and unfortunately
> not Open-Source, C++ program. I will try to reduce it to a minimal
> testcase
> as soon as I get around to it.
Okay, I wrote a minimal testcase that does just the operations that lead to
the problem, only to find out that this won't reproduce the bug either :-\
That means either I'm inadvertently triggering some rare corner case here
who knows where in my code, or the bug is really in my code. I don't think
it's the latter, though, because the relevant part of my code looks like
this:
if(virDomainCreate(vserver.get_virdomain().get()) != 0) {
// TODO clean up pointer
virErrorPtr error = virGetLastError();
if(error != 0) {
syslog(LOG_ERR, "Could not start vserver, error code: %d", error->code);
// VIR_ERR_OPERATION_INVALID means the vm was already in a started state
if(error->code != VIR_ERR_OPERATION_INVALID)
throw std::runtime_error("Could not start vserver");
}
else {
syslog(LOG_ERR, "Could not start vserver, no error code from libvirt");
throw std::runtime_error("Could not start vserver, no error code from
libvirt");
}
}
There's nothing in there between calling virDomainCreate() and
virGetLastError(). There are no other threads, either.
Anyway, I've fired up gdb now to see if I can find out where the error
object gets lost.
I found out what is happening here:
I am using a C++ wrapper class for virDomainPtr, to make it fit better with
the RAII principles in that language. That means that, in the above code
snippet, even though it's not actually visible because it happens in the
constructor and destructor of a temporary object, the virDomainPtr for domain
gets copied once, virDomainRef() gets called on it, and after the attempt to
start the domain, virDomainFree() gets called.
The problem is that virDomainFree() will unconditionally call
virResetLastError().
With that info, I could work around the problem, however, I still think that,
since virDomainFree() is a reference-counting free, it should only call
virResetLastError() when the reference count has actually reached 0. In fact,
it should probably even check whether the last error even belongs to the
domain being deleted.
Guido