提交 3a80f2f7 编写于 作者: D Daniel P. Berrange 提交者: Cole Robinson

Ensure error handling callback functions are called from safe context

The virRaiseErrorFull() may invoke the error handler callback
functions an application has registered. This is not good
because the connection object may not be available at this
point, and the caller may be holding locks. This creates a
problem if the error handler calls back into libvirt.

The solutuon is to move invocation of the handler into the
final cleanup code in the public API entry points, where it
is guarenteed to have safe state.

* src/libvirt.c: Invoke virDispatchError() in all error paths
* src/util/virterror.c: Remove virSetConnError/virSetGlobalError,
  replacing with virDispatchError(). Move invocation of the
  error callbacks into virDispatchError() instead of the
  virRaiseErrorFull function which is not in a safe context
上级 66b32505
此差异已折叠。
...@@ -560,43 +560,49 @@ virDefaultErrorFunc(virErrorPtr err) ...@@ -560,43 +560,49 @@ virDefaultErrorFunc(virErrorPtr err)
} }
/** /**
* virSetGlobalError: * virDispatchError:
* Internal helper to ensure the global error object
* is initialized with a generic message if not already
* set.
*/
void
virSetGlobalError(void)
{
virErrorPtr err = virLastErrorObject();
if (err && err->code == VIR_ERR_OK)
virErrorGenericFailure(err);
}
/**
* virSetConnError:
* @conn: pointer to the hypervisor connection * @conn: pointer to the hypervisor connection
* *
* Internal helper to ensure the connection error object * Internal helper to do final stage of error
* is initialized from the global object. * reporting in public APIs.
*
* - Copy the global error to per-connection error if needed
* - Set a generic error message if none is already set
* - Invoke the error callback functions
*/ */
void void
virSetConnError(virConnectPtr conn) virDispatchError(virConnectPtr conn)
{ {
virErrorPtr err = virLastErrorObject(); virErrorPtr err = virLastErrorObject();
virErrorFunc handler = virErrorHandler;
void *userData = virUserData;
/* Should never happen, but doesn't hurt to check */
if (!err)
return;
if (err && err->code == VIR_ERR_OK) /* Set a generic error message if none is already set */
if (err->code == VIR_ERR_OK)
virErrorGenericFailure(err); virErrorGenericFailure(err);
/* Copy the global error to per-connection error if needed */
if (conn) { if (conn) {
virMutexLock(&conn->lock); virMutexLock(&conn->lock);
if (err) virCopyError(err, &conn->err);
virCopyError(err, &conn->err);
else if (conn->handler != NULL) {
virErrorGenericFailure(&conn->err); handler = conn->handler;
userData = conn->userData;
}
virMutexUnlock(&conn->lock); virMutexUnlock(&conn->lock);
} }
/* Invoke the error callback functions */
if (handler != NULL) {
(handler)(userData, err);
} else {
virDefaultErrorFunc(err);
}
} }
...@@ -622,7 +628,7 @@ virSetConnError(virConnectPtr conn) ...@@ -622,7 +628,7 @@ virSetConnError(virConnectPtr conn)
* immediately if a callback is found and store it for later handling. * immediately if a callback is found and store it for later handling.
*/ */
void void
virRaiseErrorFull(virConnectPtr conn, virRaiseErrorFull(virConnectPtr conn ATTRIBUTE_UNUSED,
const char *filename ATTRIBUTE_UNUSED, const char *filename ATTRIBUTE_UNUSED,
const char *funcname, const char *funcname,
size_t linenr, size_t linenr,
...@@ -637,8 +643,6 @@ virRaiseErrorFull(virConnectPtr conn, ...@@ -637,8 +643,6 @@ virRaiseErrorFull(virConnectPtr conn,
const char *fmt, ...) const char *fmt, ...)
{ {
virErrorPtr to; virErrorPtr to;
void *userData = virUserData;
virErrorFunc handler = virErrorHandler;
char *str; char *str;
/* /*
...@@ -655,18 +659,6 @@ virRaiseErrorFull(virConnectPtr conn, ...@@ -655,18 +659,6 @@ virRaiseErrorFull(virConnectPtr conn,
if (code == VIR_ERR_OK) if (code == VIR_ERR_OK)
return; return;
/*
* try to find the best place to save and report the error
*/
if (conn != NULL) {
virMutexLock(&conn->lock);
if (conn->handler != NULL) {
handler = conn->handler;
userData = conn->userData;
}
virMutexUnlock(&conn->lock);
}
/* /*
* formats the message * formats the message
*/ */
...@@ -686,7 +678,6 @@ virRaiseErrorFull(virConnectPtr conn, ...@@ -686,7 +678,6 @@ virRaiseErrorFull(virConnectPtr conn,
/* /*
* Save the information about the error * Save the information about the error
*/ */
virResetError(to);
/* /*
* Delibrately not setting conn, dom & net fields since * Delibrately not setting conn, dom & net fields since
* they're utterly unsafe * they're utterly unsafe
...@@ -703,15 +694,6 @@ virRaiseErrorFull(virConnectPtr conn, ...@@ -703,15 +694,6 @@ virRaiseErrorFull(virConnectPtr conn,
to->str3 = strdup(str3); to->str3 = strdup(str3);
to->int1 = int1; to->int1 = int1;
to->int2 = int2; to->int2 = int2;
/*
* now, report it
*/
if (handler != NULL) {
handler(userData, to);
} else {
virDefaultErrorFunc(to);
}
} }
/** /**
......
...@@ -90,8 +90,7 @@ void virReportOOMErrorFull(virConnectPtr conn, ...@@ -90,8 +90,7 @@ void virReportOOMErrorFull(virConnectPtr conn,
__FILE__, __FUNCTION__, __LINE__) __FILE__, __FUNCTION__, __LINE__)
void virSetGlobalError(void); void virDispatchError(virConnectPtr conn);
void virSetConnError(virConnectPtr conn);
const char *virStrerror(int theerrno, char *errBuf, size_t errBufLen); const char *virStrerror(int theerrno, char *errBuf, size_t errBufLen);
#endif #endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册