* [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure @ 2013-03-06 10:48 Kevin Wolf 2013-03-06 11:04 ` Paolo Bonzini 2013-03-06 15:05 ` [Qemu-devel] Error ** parameter conventions (was: [PATCH] qemu-sockets: Fix assertion failure) Markus Armbruster 0 siblings, 2 replies; 24+ messages in thread From: Kevin Wolf @ 2013-03-06 10:48 UTC (permalink / raw) To: qemu-devel; +Cc: kwolf inet_connect_opts() tries all possible addrinfos returned by getaddrinfo(). If one fails with an error, the next one is tried. In this case, the Error should be discarded because the whole operation is successful if another addrinfo from the list succeeds; and if it doesn't, setting an already set Error will trigger an assertion failure. Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- util/qemu-sockets.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 1350ccc..32e609a 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -373,6 +373,14 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, } for (e = res; e != NULL; e = e->ai_next) { + + /* Overwriting errors isn't allowed, so clear any error that may have + * occured in the previous iteration */ + if (error_is_set(errp)) { + error_free(*errp); + *errp = NULL; + } + if (connect_state != NULL) { connect_state->current_addr = e; } -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-06 10:48 [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure Kevin Wolf @ 2013-03-06 11:04 ` Paolo Bonzini 2013-03-06 11:11 ` Kevin Wolf 2013-03-06 15:05 ` [Qemu-devel] Error ** parameter conventions (was: [PATCH] qemu-sockets: Fix assertion failure) Markus Armbruster 1 sibling, 1 reply; 24+ messages in thread From: Paolo Bonzini @ 2013-03-06 11:04 UTC (permalink / raw) To: Kevin Wolf; +Cc: qemu-devel Il 06/03/2013 11:48, Kevin Wolf ha scritto: > inet_connect_opts() tries all possible addrinfos returned by > getaddrinfo(). If one fails with an error, the next one is tried. In > this case, the Error should be discarded because the whole operation is > successful if another addrinfo from the list succeeds; and if it > doesn't, setting an already set Error will trigger an assertion failure. > > Signed-off-by: Kevin Wolf <kwolf@redhat.com> > --- > util/qemu-sockets.c | 8 ++++++++ > 1 file changed, 8 insertions(+) > > diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c > index 1350ccc..32e609a 100644 > --- a/util/qemu-sockets.c > +++ b/util/qemu-sockets.c > @@ -373,6 +373,14 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, > } > > for (e = res; e != NULL; e = e->ai_next) { > + > + /* Overwriting errors isn't allowed, so clear any error that may have > + * occured in the previous iteration */ > + if (error_is_set(errp)) { > + error_free(*errp); > + *errp = NULL; > + } > + > if (connect_state != NULL) { > connect_state->current_addr = e; > } > Should we also do nothing if errp is not NULL on entry? Paolo ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-06 11:04 ` Paolo Bonzini @ 2013-03-06 11:11 ` Kevin Wolf 2013-03-06 14:46 ` Laszlo Ersek 2013-03-06 15:05 ` Markus Armbruster 0 siblings, 2 replies; 24+ messages in thread From: Kevin Wolf @ 2013-03-06 11:11 UTC (permalink / raw) To: Paolo Bonzini; +Cc: qemu-devel Am 06.03.2013 um 12:04 hat Paolo Bonzini geschrieben: > Il 06/03/2013 11:48, Kevin Wolf ha scritto: > > inet_connect_opts() tries all possible addrinfos returned by > > getaddrinfo(). If one fails with an error, the next one is tried. In > > this case, the Error should be discarded because the whole operation is > > successful if another addrinfo from the list succeeds; and if it > > doesn't, setting an already set Error will trigger an assertion failure. > > > > Signed-off-by: Kevin Wolf <kwolf@redhat.com> > > --- > > util/qemu-sockets.c | 8 ++++++++ > > 1 file changed, 8 insertions(+) > > > > diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c > > index 1350ccc..32e609a 100644 > > --- a/util/qemu-sockets.c > > +++ b/util/qemu-sockets.c > > @@ -373,6 +373,14 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, > > } > > > > for (e = res; e != NULL; e = e->ai_next) { > > + > > + /* Overwriting errors isn't allowed, so clear any error that may have > > + * occured in the previous iteration */ > > + if (error_is_set(errp)) { > > + error_free(*errp); > > + *errp = NULL; > > + } > > + > > if (connect_state != NULL) { > > connect_state->current_addr = e; > > } > > > > Should we also do nothing if errp is not NULL on entry? We could assert(!error_is_set(errp)) if we wanted. As soon as you've got an Error, you must return instead of calling more functions with the same error pointer. Kevin ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-06 11:11 ` Kevin Wolf @ 2013-03-06 14:46 ` Laszlo Ersek 2013-03-06 15:04 ` Paolo Bonzini 2013-03-19 20:34 ` [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure Luiz Capitulino 2013-03-06 15:05 ` Markus Armbruster 1 sibling, 2 replies; 24+ messages in thread From: Laszlo Ersek @ 2013-03-06 14:46 UTC (permalink / raw) To: Kevin Wolf; +Cc: Paolo Bonzini, qemu-devel, Luiz Capitulino On 03/06/13 12:11, Kevin Wolf wrote: > Am 06.03.2013 um 12:04 hat Paolo Bonzini geschrieben: >> Il 06/03/2013 11:48, Kevin Wolf ha scritto: >>> inet_connect_opts() tries all possible addrinfos returned by >>> getaddrinfo(). If one fails with an error, the next one is tried. In >>> this case, the Error should be discarded because the whole operation is >>> successful if another addrinfo from the list succeeds; and if it >>> doesn't, setting an already set Error will trigger an assertion failure. >>> >>> Signed-off-by: Kevin Wolf <kwolf@redhat.com> >>> --- >>> util/qemu-sockets.c | 8 ++++++++ >>> 1 file changed, 8 insertions(+) >>> >>> diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c >>> index 1350ccc..32e609a 100644 >>> --- a/util/qemu-sockets.c >>> +++ b/util/qemu-sockets.c >>> @@ -373,6 +373,14 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, >>> } >>> >>> for (e = res; e != NULL; e = e->ai_next) { >>> + >>> + /* Overwriting errors isn't allowed, so clear any error that may have >>> + * occured in the previous iteration */ >>> + if (error_is_set(errp)) { >>> + error_free(*errp); >>> + *errp = NULL; >>> + } >>> + >>> if (connect_state != NULL) { >>> connect_state->current_addr = e; >>> } >>> >> >> Should we also do nothing if errp is not NULL on entry? > > We could assert(!error_is_set(errp)) if we wanted. As soon as you've got > an Error, you must return instead of calling more functions with the > same error pointer. I think Luiz would suggest (*) to receive any error into a NULL-initialized local_err pointer; do the logic above on local_err, and just before returning, error_propagate() it to errp. (*) I hope you can see what I did there: if you disagree, you get to take that to Luiz, even though he didn't say anything. I'm getting better at working this list! :) Laszlo ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-06 14:46 ` Laszlo Ersek @ 2013-03-06 15:04 ` Paolo Bonzini 2013-03-06 15:19 ` Kevin Wolf 2013-03-19 20:34 ` [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure Luiz Capitulino 1 sibling, 1 reply; 24+ messages in thread From: Paolo Bonzini @ 2013-03-06 15:04 UTC (permalink / raw) To: Laszlo Ersek; +Cc: Kevin Wolf, qemu-devel, Luiz Capitulino Il 06/03/2013 15:46, Laszlo Ersek ha scritto: >> > We could assert(!error_is_set(errp)) if we wanted. As soon as you've got >> > an Error, you must return instead of calling more functions with the >> > same error pointer. > I think Luiz would suggest (*) to receive any error into a > NULL-initialized local_err pointer; do the logic above on local_err, and > just before returning, error_propagate() it to errp. > > (*) I hope you can see what I did there: if you disagree, you get to > take that to Luiz, even though he didn't say anything. I'm getting > better at working this list! :) I agree with Laszlo. Paolo ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-06 15:04 ` Paolo Bonzini @ 2013-03-06 15:19 ` Kevin Wolf 2013-03-06 15:38 ` Laszlo Ersek 2013-03-06 15:59 ` Markus Armbruster 0 siblings, 2 replies; 24+ messages in thread From: Kevin Wolf @ 2013-03-06 15:19 UTC (permalink / raw) To: Paolo Bonzini; +Cc: Laszlo Ersek, qemu-devel, Luiz Capitulino Am 06.03.2013 um 16:04 hat Paolo Bonzini geschrieben: > Il 06/03/2013 15:46, Laszlo Ersek ha scritto: > >> > We could assert(!error_is_set(errp)) if we wanted. As soon as you've got > >> > an Error, you must return instead of calling more functions with the > >> > same error pointer. > > I think Luiz would suggest (*) to receive any error into a > > NULL-initialized local_err pointer; do the logic above on local_err, and > > just before returning, error_propagate() it to errp. > > > > (*) I hope you can see what I did there: if you disagree, you get to > > take that to Luiz, even though he didn't say anything. I'm getting > > better at working this list! :) > > I agree with Laszlo. I don't really understand the difference. As long as the function doesn't depend on the Error object to be present (which it doesn't), isn't it semantically exactly the same? Also, Markus' reply makes me think that I should restrict myself to code areas where errors are reported as -errno. That one I understand at least... Kevin ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-06 15:19 ` Kevin Wolf @ 2013-03-06 15:38 ` Laszlo Ersek 2013-03-06 15:47 ` Kevin Wolf 2013-03-06 15:59 ` Markus Armbruster 1 sibling, 1 reply; 24+ messages in thread From: Laszlo Ersek @ 2013-03-06 15:38 UTC (permalink / raw) To: Kevin Wolf; +Cc: Paolo Bonzini, qemu-devel, Luiz Capitulino On 03/06/13 16:19, Kevin Wolf wrote: > Am 06.03.2013 um 16:04 hat Paolo Bonzini geschrieben: >> Il 06/03/2013 15:46, Laszlo Ersek ha scritto: >>>>> We could assert(!error_is_set(errp)) if we wanted. As soon as you've got >>>>> an Error, you must return instead of calling more functions with the >>>>> same error pointer. >>> I think Luiz would suggest (*) to receive any error into a >>> NULL-initialized local_err pointer; do the logic above on local_err, and >>> just before returning, error_propagate() it to errp. >>> >>> (*) I hope you can see what I did there: if you disagree, you get to >>> take that to Luiz, even though he didn't say anything. I'm getting >>> better at working this list! :) >> >> I agree with Laszlo. > > I don't really understand the difference. As long as the function > doesn't depend on the Error object to be present (which it doesn't), > isn't it semantically exactly the same? The difference is when the caller passes in an already set Error. In this case you release that and replace it with your own error. Usually we stick to the first error encountered. Under the above suggestion you'd keep error handling internal to yourself, and in the end make one attempt to propagate it outwards. If the caller has passed in NULL, the error is dropped. If the caller's passed in a preexistent error, then that one takes precedence and the new one is dropped (but it doesn't interfere with the internal logic). Third, the caller can even accept your error. error_propagate() and error_set() deal with the overwrite attempt differently. The former silently drops the newcomer, whereas the latter assert()s. Of course one wonders why a caller would pass in a preexistent Error. Laszlo ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-06 15:38 ` Laszlo Ersek @ 2013-03-06 15:47 ` Kevin Wolf 2013-03-06 16:04 ` Laszlo Ersek 0 siblings, 1 reply; 24+ messages in thread From: Kevin Wolf @ 2013-03-06 15:47 UTC (permalink / raw) To: Laszlo Ersek; +Cc: Paolo Bonzini, qemu-devel, Luiz Capitulino Am 06.03.2013 um 16:38 hat Laszlo Ersek geschrieben: > On 03/06/13 16:19, Kevin Wolf wrote: > > Am 06.03.2013 um 16:04 hat Paolo Bonzini geschrieben: > >> Il 06/03/2013 15:46, Laszlo Ersek ha scritto: > >>>>> We could assert(!error_is_set(errp)) if we wanted. As soon as you've got > >>>>> an Error, you must return instead of calling more functions with the > >>>>> same error pointer. > >>> I think Luiz would suggest (*) to receive any error into a > >>> NULL-initialized local_err pointer; do the logic above on local_err, and > >>> just before returning, error_propagate() it to errp. > >>> > >>> (*) I hope you can see what I did there: if you disagree, you get to > >>> take that to Luiz, even though he didn't say anything. I'm getting > >>> better at working this list! :) > >> > >> I agree with Laszlo. > > > > I don't really understand the difference. As long as the function > > doesn't depend on the Error object to be present (which it doesn't), > > isn't it semantically exactly the same? > > The difference is when the caller passes in an already set Error. In > this case you release that and replace it with your own error. > > Usually we stick to the first error encountered. Under the above > suggestion you'd keep error handling internal to yourself, and in the > end make one attempt to propagate it outwards. If the caller has passed > in NULL, the error is dropped. If the caller's passed in a preexistent > error, then that one takes precedence and the new one is dropped (but it > doesn't interfere with the internal logic). Third, the caller can even > accept your error. > > error_propagate() and error_set() deal with the overwrite attempt > differently. The former silently drops the newcomer, whereas the latter > assert()s. > > Of course one wonders why a caller would pass in a preexistent Error. Thanks, Laszlo, now I think I understand what Paolo and you were suggesting. However, I'd call any such caller buggy and don't feel like adding code so that it doesn't break. This is what I meant when I said you should return when you get an error, and not call other functions with the already used error pointer. Kevin ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-06 15:47 ` Kevin Wolf @ 2013-03-06 16:04 ` Laszlo Ersek 0 siblings, 0 replies; 24+ messages in thread From: Laszlo Ersek @ 2013-03-06 16:04 UTC (permalink / raw) To: Kevin Wolf; +Cc: Paolo Bonzini, qemu-devel, Luiz Capitulino On 03/06/13 16:47, Kevin Wolf wrote: > Am 06.03.2013 um 16:38 hat Laszlo Ersek geschrieben: >> Of course one wonders why a caller would pass in a preexistent Error. > > Thanks, Laszlo, now I think I understand what Paolo and you were > suggesting. > > However, I'd call any such caller buggy and don't feel like adding code > so that it doesn't break. This is what I meant when I said you should > return when you get an error, and not call other functions with the > already used error pointer. I don't disagree. I'm certainly not blocking your patch! :) Laszlo ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-06 15:19 ` Kevin Wolf 2013-03-06 15:38 ` Laszlo Ersek @ 2013-03-06 15:59 ` Markus Armbruster 2013-03-06 16:43 ` Paolo Bonzini 2013-03-14 14:57 ` [Qemu-devel] [RFC PATCH] qemu-socket: Use local error variable Kevin Wolf 1 sibling, 2 replies; 24+ messages in thread From: Markus Armbruster @ 2013-03-06 15:59 UTC (permalink / raw) To: Kevin Wolf; +Cc: Paolo Bonzini, Laszlo Ersek, qemu-devel, Luiz Capitulino Kevin Wolf <kwolf@redhat.com> writes: > Am 06.03.2013 um 16:04 hat Paolo Bonzini geschrieben: >> Il 06/03/2013 15:46, Laszlo Ersek ha scritto: >> >> > We could assert(!error_is_set(errp)) if we wanted. As soon as you've got >> >> > an Error, you must return instead of calling more functions with the >> >> > same error pointer. >> > I think Luiz would suggest (*) to receive any error into a >> > NULL-initialized local_err pointer; do the logic above on local_err, and >> > just before returning, error_propagate() it to errp. >> > >> > (*) I hope you can see what I did there: if you disagree, you get to >> > take that to Luiz, even though he didn't say anything. I'm getting >> > better at working this list! :) >> >> I agree with Laszlo. > > I don't really understand the difference. As long as the function > doesn't depend on the Error object to be present (which it doesn't), > isn't it semantically exactly the same? I guess it is in this case (I didn't call your patch wrong). However, I figure that as soon as we go beyond utterly trivial with errors, it's advisable to put them in local variables, and error_propagate() to the parameter only at the end. Messing around with errp parameters directly feels error-prone, and I'm afraid even correct messing could easily lead to incorrect messing, when folks imitate it without really understanding what they're doing. Yes, extra local variables make the error propagation code even bulkier. No, I don't like it any more than you do. > Also, Markus' reply makes me think that I should restrict myself to code > areas where errors are reported as -errno. That one I understand at > least... I wish I could, but I stepped into the error swamp long ago, and the muck is still sticking to my heels. Whenever a simple error reporting mechanism such as non-null/null or non-negative/-errno suffices, I very much recommend to use it. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-06 15:59 ` Markus Armbruster @ 2013-03-06 16:43 ` Paolo Bonzini 2013-03-14 14:57 ` [Qemu-devel] [RFC PATCH] qemu-socket: Use local error variable Kevin Wolf 1 sibling, 0 replies; 24+ messages in thread From: Paolo Bonzini @ 2013-03-06 16:43 UTC (permalink / raw) To: Markus Armbruster; +Cc: Kevin Wolf, Laszlo Ersek, qemu-devel, Luiz Capitulino Il 06/03/2013 16:59, Markus Armbruster ha scritto: >> > >> > I don't really understand the difference. As long as the function >> > doesn't depend on the Error object to be present (which it doesn't), >> > isn't it semantically exactly the same? > I guess it is in this case (I didn't call your patch wrong). However, I > figure that as soon as we go beyond utterly trivial with errors, it's > advisable to put them in local variables, and error_propagate() to the > parameter only at the end. Messing around with errp parameters directly > feels error-prone, and I'm afraid even correct messing could easily lead > to incorrect messing, when folks imitate it without really understanding > what they're doing. Yes, that's my thought more or less. However, the possibilities are: 1) asserting that there is no error. We hardly ever do this, and it's not clear to me that we should start. It would introduce one more error-propagation idiom, and more confusion. 2) do nothing if there is an error. This is what for example the QAPI visitors do. 3) what Laszlo suggested. However, it is almost certainly a bug to call this function with a pre-existing error, because this function has quite "strong" side effects. Hence this might mask a bug and leave pending connections. 4) just your patch. This is just as wrong as (3) if there was a pre-existing error, and it also overwrites the pre-existing error; harder to debug, and inconsistent with functions using the local variables. None is optimal, but (2) seems the best. Paolo > Yes, extra local variables make the error propagation code even bulkier. > No, I don't like it any more than you do. ^ permalink raw reply [flat|nested] 24+ messages in thread
* [Qemu-devel] [RFC PATCH] qemu-socket: Use local error variable 2013-03-06 15:59 ` Markus Armbruster 2013-03-06 16:43 ` Paolo Bonzini @ 2013-03-14 14:57 ` Kevin Wolf 2013-03-14 15:52 ` Laszlo Ersek 1 sibling, 1 reply; 24+ messages in thread From: Kevin Wolf @ 2013-03-14 14:57 UTC (permalink / raw) To: qemu-devel; +Cc: kwolf, pbonzini, lersek, armbru Signed-off-by: Kevin Wolf <kwolf@redhat.com> --- After rebasing this I saw that Anthony already committed a fix that is very close to my v1. I don't intend to actually change that code, but as I've already done this, just for comparison what it would look like with error propagation. Is this what you meant? I find the result more confusing, to be honest. --- util/qemu-sockets.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 3f12296..f231e9c 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -359,6 +359,7 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, int sock = -1; bool in_progress; ConnectState *connect_state = NULL; + Error *local_err = NULL; res = inet_parse_connect_opts(opts, errp); if (!res) { @@ -373,15 +374,17 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, } for (e = res; e != NULL; e = e->ai_next) { - if (error_is_set(errp)) { - error_free(*errp); - *errp = NULL; - } + + Error *ret_err = NULL; + if (connect_state != NULL) { connect_state->current_addr = e; } - sock = inet_connect_addr(e, &in_progress, connect_state, errp); - if (in_progress) { + sock = inet_connect_addr(e, &in_progress, connect_state, &ret_err); + if (error_is_set(&ret_err)) { + error_propagate(&local_err, ret_err); + } else if (in_progress) { + error_free(local_err); return sock; } else if (sock >= 0) { /* non blocking socket immediate success, call callback */ @@ -393,6 +396,11 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, } g_free(connect_state); freeaddrinfo(res); + if (sock >= 0) { + error_free(local_err); + } else { + error_propagate(errp, local_err); + } return sock; } -- 1.8.1.4 ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [RFC PATCH] qemu-socket: Use local error variable 2013-03-14 14:57 ` [Qemu-devel] [RFC PATCH] qemu-socket: Use local error variable Kevin Wolf @ 2013-03-14 15:52 ` Laszlo Ersek 2013-03-15 8:37 ` Kevin Wolf 0 siblings, 1 reply; 24+ messages in thread From: Laszlo Ersek @ 2013-03-14 15:52 UTC (permalink / raw) To: Kevin Wolf; +Cc: pbonzini, qemu-devel, armbru On 03/14/13 15:57, Kevin Wolf wrote: > Signed-off-by: Kevin Wolf <kwolf@redhat.com> > --- > After rebasing this I saw that Anthony already committed a fix that is > very close to my v1. I don't intend to actually change that code, but as > I've already done this, just for comparison what it would look like with > error propagation. Is this what you meant? I find the result more > confusing, to be honest. I think what I had in mind was: - I was okay with the logic change you suggested in your v1, just - turn *errp accesses into local_err accesses, - when returning, propagate the latter to the former. The logic seemed OK, I just suggested to keep the massage internal to the function, only try to propagate it outwards at return time. IOW, never read *errp. Laszlo ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [RFC PATCH] qemu-socket: Use local error variable 2013-03-14 15:52 ` Laszlo Ersek @ 2013-03-15 8:37 ` Kevin Wolf 2013-03-15 16:55 ` Laszlo Ersek 0 siblings, 1 reply; 24+ messages in thread From: Kevin Wolf @ 2013-03-15 8:37 UTC (permalink / raw) To: Laszlo Ersek; +Cc: pbonzini, qemu-devel, armbru Am 14.03.2013 um 16:52 hat Laszlo Ersek geschrieben: > On 03/14/13 15:57, Kevin Wolf wrote: > > Signed-off-by: Kevin Wolf <kwolf@redhat.com> > > --- > > After rebasing this I saw that Anthony already committed a fix that is > > very close to my v1. I don't intend to actually change that code, but as > > I've already done this, just for comparison what it would look like with > > error propagation. Is this what you meant? I find the result more > > confusing, to be honest. > > I think what I had in mind was: > - I was okay with the logic change you suggested in your v1, just > - turn *errp accesses into local_err accesses, > - when returning, propagate the latter to the former. > > The logic seemed OK, I just suggested to keep the massage internal to > the function, only try to propagate it outwards at return time. IOW, > never read *errp. So you would have used my local_err, but not ret_err? I don't think that would make it much better, ret_err is actually the nice part. Kevin ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [RFC PATCH] qemu-socket: Use local error variable 2013-03-15 8:37 ` Kevin Wolf @ 2013-03-15 16:55 ` Laszlo Ersek 2013-03-15 17:55 ` Kevin Wolf 0 siblings, 1 reply; 24+ messages in thread From: Laszlo Ersek @ 2013-03-15 16:55 UTC (permalink / raw) To: Kevin Wolf; +Cc: pbonzini, qemu-devel, armbru On 03/15/13 09:37, Kevin Wolf wrote: > Am 14.03.2013 um 16:52 hat Laszlo Ersek geschrieben: >> On 03/14/13 15:57, Kevin Wolf wrote: >>> Signed-off-by: Kevin Wolf <kwolf@redhat.com> >>> --- >>> After rebasing this I saw that Anthony already committed a fix that is >>> very close to my v1. I don't intend to actually change that code, but as >>> I've already done this, just for comparison what it would look like with >>> error propagation. Is this what you meant? I find the result more >>> confusing, to be honest. >> >> I think what I had in mind was: >> - I was okay with the logic change you suggested in your v1, just >> - turn *errp accesses into local_err accesses, >> - when returning, propagate the latter to the former. >> >> The logic seemed OK, I just suggested to keep the massage internal to >> the function, only try to propagate it outwards at return time. IOW, >> never read *errp. > > So you would have used my local_err, but not ret_err? Something like that, yes. > I don't think that > would make it much better, Not contesting that ;) > ret_err is actually the nice part. Anyway I'm not feeling strongly about this and I don't want to waste your time with it. It was just a note in passing. (... Which I should probably refrain from, lest I waste people's time.) L. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [RFC PATCH] qemu-socket: Use local error variable 2013-03-15 16:55 ` Laszlo Ersek @ 2013-03-15 17:55 ` Kevin Wolf 2013-03-15 18:39 ` Laszlo Ersek 0 siblings, 1 reply; 24+ messages in thread From: Kevin Wolf @ 2013-03-15 17:55 UTC (permalink / raw) To: Laszlo Ersek; +Cc: pbonzini, qemu-devel, armbru Am 15.03.2013 um 17:55 hat Laszlo Ersek geschrieben: > On 03/15/13 09:37, Kevin Wolf wrote: > > Am 14.03.2013 um 16:52 hat Laszlo Ersek geschrieben: > >> On 03/14/13 15:57, Kevin Wolf wrote: > >>> Signed-off-by: Kevin Wolf <kwolf@redhat.com> > >>> --- > >>> After rebasing this I saw that Anthony already committed a fix that is > >>> very close to my v1. I don't intend to actually change that code, but as > >>> I've already done this, just for comparison what it would look like with > >>> error propagation. Is this what you meant? I find the result more > >>> confusing, to be honest. > >> > >> I think what I had in mind was: > >> - I was okay with the logic change you suggested in your v1, just > >> - turn *errp accesses into local_err accesses, > >> - when returning, propagate the latter to the former. > >> > >> The logic seemed OK, I just suggested to keep the massage internal to > >> the function, only try to propagate it outwards at return time. IOW, > >> never read *errp. > > > > So you would have used my local_err, but not ret_err? > > Something like that, yes. > > > I don't think that > > would make it much better, > > Not contesting that ;) > > > ret_err is actually the nice part. > > Anyway I'm not feeling strongly about this and I don't want to waste > your time with it. It was just a note in passing. (... Which I should > probably refrain from, lest I waste people's time.) I'm not going to change this instance anyway now that Anthony pushed his own fix instead of mine. However this won't be the last time that I have to deal with an Error object, so I thought I'd check what is good practice. Seems no such thing has established yet, which is an answer, even though not the one I was hoping for. Kevin ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [RFC PATCH] qemu-socket: Use local error variable 2013-03-15 17:55 ` Kevin Wolf @ 2013-03-15 18:39 ` Laszlo Ersek 0 siblings, 0 replies; 24+ messages in thread From: Laszlo Ersek @ 2013-03-15 18:39 UTC (permalink / raw) To: Kevin Wolf; +Cc: pbonzini, qemu-devel, armbru On 03/15/13 18:55, Kevin Wolf wrote: > However this won't be the last time that I have to deal with an Error > object, so I thought I'd check what is good practice. Seems no such > thing has established yet, which is an answer, even though not the one I > was hoping for. What I've gathered from discussions with Luiz and Markus, there is indeed no official Error*-handling-style. FWIW personally I think that my suggestion was quite close to a good (I'd even hazard "elegant") approach. I did notice that it would look terrible in the function at hand if applied directly (I actually started to code it up as an "illustrative patch"). For the emergent fugliness I blamed inet_connect_opts()'s current structure (several exit points, transfer of ownership without documentation, etc). So for the illustration I would have had to restructure the function. That in turn would have depended on me understanding the non-trivial life cycle (ownership) of "connect_state" / "res" under the different return conditions. (That is, when we bail out due to "in progress", the "connect_state" and the rest of the addrinfo list is: - either referenced elsewhere, - or freed, - or leaked currently.) I didn't (don't) have time/energy for that -- my bad. In general, murky ownership transfers seem to be characteristic of qemu. When a function allocates dynamic memory, it should: (1) either free it unconditionally (temp working space), (2) free it on error, return it on success (constructor), (3) transfer the ownership by function call (huge comment or telling function name). This includes any refcount increments by the callee. ... The function name "inet_connect_addr" tells us nothing about qemu_set_fd_handler2() transferring the ownership of "connect_state" (and the off-hanging addrinfo list) to the global "io_handlers". inet_connect_opts inet_connect_addr qemu_set_fd_handler2 ownership transfer in one case release stuff in two other cases Thanks, Laszlo ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-06 14:46 ` Laszlo Ersek 2013-03-06 15:04 ` Paolo Bonzini @ 2013-03-19 20:34 ` Luiz Capitulino 2013-03-20 8:39 ` Kevin Wolf 1 sibling, 1 reply; 24+ messages in thread From: Luiz Capitulino @ 2013-03-19 20:34 UTC (permalink / raw) To: Laszlo Ersek; +Cc: Kevin Wolf, Paolo Bonzini, aliguori, qemu-devel On Wed, 06 Mar 2013 15:46:45 +0100 Laszlo Ersek <lersek@redhat.com> wrote: > On 03/06/13 12:11, Kevin Wolf wrote: > > Am 06.03.2013 um 12:04 hat Paolo Bonzini geschrieben: > >> Il 06/03/2013 11:48, Kevin Wolf ha scritto: > >>> inet_connect_opts() tries all possible addrinfos returned by > >>> getaddrinfo(). If one fails with an error, the next one is tried. In > >>> this case, the Error should be discarded because the whole operation is > >>> successful if another addrinfo from the list succeeds; and if it > >>> doesn't, setting an already set Error will trigger an assertion failure. > >>> > >>> Signed-off-by: Kevin Wolf <kwolf@redhat.com> > >>> --- > >>> util/qemu-sockets.c | 8 ++++++++ > >>> 1 file changed, 8 insertions(+) > >>> > >>> diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c > >>> index 1350ccc..32e609a 100644 > >>> --- a/util/qemu-sockets.c > >>> +++ b/util/qemu-sockets.c > >>> @@ -373,6 +373,14 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, > >>> } > >>> > >>> for (e = res; e != NULL; e = e->ai_next) { > >>> + > >>> + /* Overwriting errors isn't allowed, so clear any error that may have > >>> + * occured in the previous iteration */ > >>> + if (error_is_set(errp)) { > >>> + error_free(*errp); > >>> + *errp = NULL; > >>> + } > >>> + > >>> if (connect_state != NULL) { > >>> connect_state->current_addr = e; > >>> } > >>> > >> > >> Should we also do nothing if errp is not NULL on entry? > > > > We could assert(!error_is_set(errp)) if we wanted. As soon as you've got > > an Error, you must return instead of calling more functions with the > > same error pointer. > > I think Luiz would suggest (*) to receive any error into a > NULL-initialized local_err pointer; do the logic above on local_err, and > just before returning, error_propagate() it to errp. Yes, I'd suggest that but it turns out that inet_connect_addr() error reporting was and still is confusing, which causes callers to use it incorrectly. This patch (which has been applied by Anthony) solves the problem at hand but it also introduces a new issue: errors from inet_connect_addr() are only reported if they happen in the last loop interaction. Note that a few other errors other than 'couldn't connect' can happen. Laszlo's comment seemed to have triggered a discussion around Error **, but this really has very little to do with it: the real problem is that inet_connect_addr() is too confusing. inet_connect_addr() has two users: inet_connect_opts() and wait_for_connect(), with this patch both of them are now ignoring errors from inet_connect_addr(). Suggested solution: refactor inet_connect_addr() to return an errno value. Callers use error_set() when they want to report an error upward. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-19 20:34 ` [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure Luiz Capitulino @ 2013-03-20 8:39 ` Kevin Wolf 2013-03-20 12:57 ` Luiz Capitulino 0 siblings, 1 reply; 24+ messages in thread From: Kevin Wolf @ 2013-03-20 8:39 UTC (permalink / raw) To: Luiz Capitulino; +Cc: Paolo Bonzini, aliguori, Laszlo Ersek, qemu-devel Am 19.03.2013 um 21:34 hat Luiz Capitulino geschrieben: > On Wed, 06 Mar 2013 15:46:45 +0100 > Laszlo Ersek <lersek@redhat.com> wrote: > > > On 03/06/13 12:11, Kevin Wolf wrote: > > > Am 06.03.2013 um 12:04 hat Paolo Bonzini geschrieben: > > >> Il 06/03/2013 11:48, Kevin Wolf ha scritto: > > >>> inet_connect_opts() tries all possible addrinfos returned by > > >>> getaddrinfo(). If one fails with an error, the next one is tried. In > > >>> this case, the Error should be discarded because the whole operation is > > >>> successful if another addrinfo from the list succeeds; and if it > > >>> doesn't, setting an already set Error will trigger an assertion failure. > > >>> > > >>> Signed-off-by: Kevin Wolf <kwolf@redhat.com> > > >>> --- > > >>> util/qemu-sockets.c | 8 ++++++++ > > >>> 1 file changed, 8 insertions(+) > > >>> > > >>> diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c > > >>> index 1350ccc..32e609a 100644 > > >>> --- a/util/qemu-sockets.c > > >>> +++ b/util/qemu-sockets.c > > >>> @@ -373,6 +373,14 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, > > >>> } > > >>> > > >>> for (e = res; e != NULL; e = e->ai_next) { > > >>> + > > >>> + /* Overwriting errors isn't allowed, so clear any error that may have > > >>> + * occured in the previous iteration */ > > >>> + if (error_is_set(errp)) { > > >>> + error_free(*errp); > > >>> + *errp = NULL; > > >>> + } > > >>> + > > >>> if (connect_state != NULL) { > > >>> connect_state->current_addr = e; > > >>> } > > >>> > > >> > > >> Should we also do nothing if errp is not NULL on entry? > > > > > > We could assert(!error_is_set(errp)) if we wanted. As soon as you've got > > > an Error, you must return instead of calling more functions with the > > > same error pointer. > > > > I think Luiz would suggest (*) to receive any error into a > > NULL-initialized local_err pointer; do the logic above on local_err, and > > just before returning, error_propagate() it to errp. > > Yes, I'd suggest that but it turns out that inet_connect_addr() error > reporting was and still is confusing, which causes callers to use it > incorrectly. > > This patch (which has been applied by Anthony) No, Anthony applied a different, but similar patch of his own. This is why I don't feel particularly responsible for the specific problem any more. How to do error handling with Error right is the only reason for me to continue the discussion. > solves the problem at > hand but it also introduces a new issue: errors from inet_connect_addr() > are only reported if they happen in the last loop interaction. Note that > a few other errors other than 'couldn't connect' can happen. > Laszlo's comment seemed to have triggered a discussion around Error **, > but this really has very little to do with it: the real problem is that > inet_connect_addr() is too confusing. Maybe we need to discuss first what the intended behaviour even is. My interpretation was this: We may have several addresses to try. If one of them works, the function as a whole has succeeded and must not return an error, neither in errp nor as -errno. If none of them succeeds, the function has to return an error, and returning the error of the last attempt is as good as the error of any other attempt. > inet_connect_addr() has two users: inet_connect_opts() and wait_for_connect(), > with this patch both of them are now ignoring errors from inet_connect_addr(). > > Suggested solution: refactor inet_connect_addr() to return an errno value. > Callers use error_set() when they want to report an error upward. Doesn't change the problem that you need to know when to set a return value != 0. So it doesn't help, but you'd lose some error information. Kevin ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-20 8:39 ` Kevin Wolf @ 2013-03-20 12:57 ` Luiz Capitulino 2013-03-20 13:37 ` Kevin Wolf 0 siblings, 1 reply; 24+ messages in thread From: Luiz Capitulino @ 2013-03-20 12:57 UTC (permalink / raw) To: Kevin Wolf; +Cc: Paolo Bonzini, aliguori, Laszlo Ersek, qemu-devel On Wed, 20 Mar 2013 09:39:34 +0100 Kevin Wolf <kwolf@redhat.com> wrote: > Am 19.03.2013 um 21:34 hat Luiz Capitulino geschrieben: > > On Wed, 06 Mar 2013 15:46:45 +0100 > > Laszlo Ersek <lersek@redhat.com> wrote: > > > > > On 03/06/13 12:11, Kevin Wolf wrote: > > > > Am 06.03.2013 um 12:04 hat Paolo Bonzini geschrieben: > > > >> Il 06/03/2013 11:48, Kevin Wolf ha scritto: > > > >>> inet_connect_opts() tries all possible addrinfos returned by > > > >>> getaddrinfo(). If one fails with an error, the next one is tried. In > > > >>> this case, the Error should be discarded because the whole operation is > > > >>> successful if another addrinfo from the list succeeds; and if it > > > >>> doesn't, setting an already set Error will trigger an assertion failure. > > > >>> > > > >>> Signed-off-by: Kevin Wolf <kwolf@redhat.com> > > > >>> --- > > > >>> util/qemu-sockets.c | 8 ++++++++ > > > >>> 1 file changed, 8 insertions(+) > > > >>> > > > >>> diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c > > > >>> index 1350ccc..32e609a 100644 > > > >>> --- a/util/qemu-sockets.c > > > >>> +++ b/util/qemu-sockets.c > > > >>> @@ -373,6 +373,14 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, > > > >>> } > > > >>> > > > >>> for (e = res; e != NULL; e = e->ai_next) { > > > >>> + > > > >>> + /* Overwriting errors isn't allowed, so clear any error that may have > > > >>> + * occured in the previous iteration */ > > > >>> + if (error_is_set(errp)) { > > > >>> + error_free(*errp); > > > >>> + *errp = NULL; > > > >>> + } > > > >>> + > > > >>> if (connect_state != NULL) { > > > >>> connect_state->current_addr = e; > > > >>> } > > > >>> > > > >> > > > >> Should we also do nothing if errp is not NULL on entry? > > > > > > > > We could assert(!error_is_set(errp)) if we wanted. As soon as you've got > > > > an Error, you must return instead of calling more functions with the > > > > same error pointer. > > > > > > I think Luiz would suggest (*) to receive any error into a > > > NULL-initialized local_err pointer; do the logic above on local_err, and > > > just before returning, error_propagate() it to errp. > > > > Yes, I'd suggest that but it turns out that inet_connect_addr() error > > reporting was and still is confusing, which causes callers to use it > > incorrectly. > > > > This patch (which has been applied by Anthony) > > No, Anthony applied a different, but similar patch of his own. This is > why I don't feel particularly responsible for the specific problem any > more. > > How to do error handling with Error right is the only reason for me to > continue the discussion. I think we need a kind of "Error best practices" doc. > > solves the problem at > > hand but it also introduces a new issue: errors from inet_connect_addr() > > are only reported if they happen in the last loop interaction. Note that > > a few other errors other than 'couldn't connect' can happen. > > > Laszlo's comment seemed to have triggered a discussion around Error **, > > but this really has very little to do with it: the real problem is that > > inet_connect_addr() is too confusing. > > Maybe we need to discuss first what the intended behaviour even is. My > interpretation was this: We may have several addresses to try. If one of > them works, the function as a whole has succeeded and must not return an > error, neither in errp nor as -errno. If none of them succeeds, the > function has to return an error, and returning the error of the last > attempt is as good as the error of any other attempt. I agree. When I looked at the code yesterday I had the impression that several other errors where possible, which made me wonder if we shouldn't stop short the loop on non-"can't connect" type of errors. But looking at it again we have only socket() and connect() calls, and I'd expect that most (all?) non can't connect errors will happen in all loop iterations, which will cause the error to be reported. > > inet_connect_addr() has two users: inet_connect_opts() and wait_for_connect(), > > with this patch both of them are now ignoring errors from inet_connect_addr(). > > > > Suggested solution: refactor inet_connect_addr() to return an errno value. > > Callers use error_set() when they want to report an error upward. > > Doesn't change the problem that you need to know when to set a return > value != 0. So it doesn't help, but you'd lose some error information. My real point is that it's easier to check against errno to find out the error cause (compared to using Error for that). ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-20 12:57 ` Luiz Capitulino @ 2013-03-20 13:37 ` Kevin Wolf 2013-03-20 13:52 ` Luiz Capitulino 0 siblings, 1 reply; 24+ messages in thread From: Kevin Wolf @ 2013-03-20 13:37 UTC (permalink / raw) To: Luiz Capitulino; +Cc: Paolo Bonzini, aliguori, Laszlo Ersek, qemu-devel Am 20.03.2013 um 13:57 hat Luiz Capitulino geschrieben: > On Wed, 20 Mar 2013 09:39:34 +0100 > Kevin Wolf <kwolf@redhat.com> wrote: > > > Am 19.03.2013 um 21:34 hat Luiz Capitulino geschrieben: > > > inet_connect_addr() has two users: inet_connect_opts() and wait_for_connect(), > > > with this patch both of them are now ignoring errors from inet_connect_addr(). > > > > > > Suggested solution: refactor inet_connect_addr() to return an errno value. > > > Callers use error_set() when they want to report an error upward. > > > > Doesn't change the problem that you need to know when to set a return > > value != 0. So it doesn't help, but you'd lose some error information. > > My real point is that it's easier to check against errno to find out > the error cause (compared to using Error for that). You mean if the caller has to distinguish between different error codes? I think I would agree that avoiding Error can be a good way then if it doesn't lose error information. If we would lose information, using error classes other than generic would be acceptable, right? In the specific case, I don't think the callers make any difference and all errors are just errors, so this is mostly about the theory. Kevin ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-20 13:37 ` Kevin Wolf @ 2013-03-20 13:52 ` Luiz Capitulino 0 siblings, 0 replies; 24+ messages in thread From: Luiz Capitulino @ 2013-03-20 13:52 UTC (permalink / raw) To: Kevin Wolf; +Cc: Paolo Bonzini, aliguori, Laszlo Ersek, qemu-devel On Wed, 20 Mar 2013 14:37:59 +0100 Kevin Wolf <kwolf@redhat.com> wrote: > Am 20.03.2013 um 13:57 hat Luiz Capitulino geschrieben: > > On Wed, 20 Mar 2013 09:39:34 +0100 > > Kevin Wolf <kwolf@redhat.com> wrote: > > > > > Am 19.03.2013 um 21:34 hat Luiz Capitulino geschrieben: > > > > inet_connect_addr() has two users: inet_connect_opts() and wait_for_connect(), > > > > with this patch both of them are now ignoring errors from inet_connect_addr(). > > > > > > > > Suggested solution: refactor inet_connect_addr() to return an errno value. > > > > Callers use error_set() when they want to report an error upward. > > > > > > Doesn't change the problem that you need to know when to set a return > > > value != 0. So it doesn't help, but you'd lose some error information. > > > > My real point is that it's easier to check against errno to find out > > the error cause (compared to using Error for that). > > You mean if the caller has to distinguish between different error codes? Yes. > I think I would agree that avoiding Error can be a good way then if it > doesn't lose error information. If we would lose information, using > error classes other than generic would be acceptable, right? Yes, I think so. I mean, even to me it's not entirely clear when new classes should be added. The rule I had in mind was that a new class should be added when a QMP client needs to distinguish a specific error. However, we're considering QEMU subsystems to be QMP clients, which (taken to an extreme) would lead us to our recent past where Error was trying to replace errno. Markus once wrote about where to set boundaries between errno and Error, but I don't remember if it was a private discussion or an email to the list. It's time to write this down in docs/. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure 2013-03-06 11:11 ` Kevin Wolf 2013-03-06 14:46 ` Laszlo Ersek @ 2013-03-06 15:05 ` Markus Armbruster 1 sibling, 0 replies; 24+ messages in thread From: Markus Armbruster @ 2013-03-06 15:05 UTC (permalink / raw) To: Kevin Wolf; +Cc: Paolo Bonzini, qemu-devel Kevin Wolf <kwolf@redhat.com> writes: > Am 06.03.2013 um 12:04 hat Paolo Bonzini geschrieben: >> Il 06/03/2013 11:48, Kevin Wolf ha scritto: >> > inet_connect_opts() tries all possible addrinfos returned by >> > getaddrinfo(). If one fails with an error, the next one is tried. In >> > this case, the Error should be discarded because the whole operation is >> > successful if another addrinfo from the list succeeds; and if it >> > doesn't, setting an already set Error will trigger an assertion failure. >> > >> > Signed-off-by: Kevin Wolf <kwolf@redhat.com> >> > --- >> > util/qemu-sockets.c | 8 ++++++++ >> > 1 file changed, 8 insertions(+) >> > >> > diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c >> > index 1350ccc..32e609a 100644 >> > --- a/util/qemu-sockets.c >> > +++ b/util/qemu-sockets.c >> > @@ -373,6 +373,14 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, >> > } >> > >> > for (e = res; e != NULL; e = e->ai_next) { >> > + >> > + /* Overwriting errors isn't allowed, so clear any error that may have >> > + * occured in the previous iteration */ >> > + if (error_is_set(errp)) { >> > + error_free(*errp); >> > + *errp = NULL; >> > + } >> > + >> > if (connect_state != NULL) { >> > connect_state->current_addr = e; >> > } >> > >> >> Should we also do nothing if errp is not NULL on entry? > > We could assert(!error_is_set(errp)) if we wanted. As soon as you've got > an Error, you must return instead of calling more functions with the > same error pointer. I wouldn't bother asserting this just here. It's a pervasive issue. We already got an assert() that covers actual error overwrites, in error_set(). ^ permalink raw reply [flat|nested] 24+ messages in thread
* [Qemu-devel] Error ** parameter conventions (was: [PATCH] qemu-sockets: Fix assertion failure) 2013-03-06 10:48 [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure Kevin Wolf 2013-03-06 11:04 ` Paolo Bonzini @ 2013-03-06 15:05 ` Markus Armbruster 1 sibling, 0 replies; 24+ messages in thread From: Markus Armbruster @ 2013-03-06 15:05 UTC (permalink / raw) To: Kevin Wolf; +Cc: qemu-devel, Luiz Capitulino [Note cc: Luiz] Kevin Wolf <kwolf@redhat.com> writes: > inet_connect_opts() tries all possible addrinfos returned by > getaddrinfo(). If one fails with an error, the next one is tried. In > this case, the Error should be discarded because the whole operation is > successful if another addrinfo from the list succeeds; and if it > doesn't, setting an already set Error will trigger an assertion failure. > > Signed-off-by: Kevin Wolf <kwolf@redhat.com> > --- > util/qemu-sockets.c | 8 ++++++++ > 1 file changed, 8 insertions(+) > > diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c > index 1350ccc..32e609a 100644 > --- a/util/qemu-sockets.c > +++ b/util/qemu-sockets.c > @@ -373,6 +373,14 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, > } > > for (e = res; e != NULL; e = e->ai_next) { > + > + /* Overwriting errors isn't allowed, so clear any error that may have > + * occured in the previous iteration */ > + if (error_is_set(errp)) { > + error_free(*errp); > + *errp = NULL; > + } > + > if (connect_state != NULL) { > connect_state->current_addr = e; > } I'm not sure this is the proper solution, but that could be just my uncertainty on proper Error usage. The convention as I understand it is that a function stores whatever error it wants to return through its errp parameter, with error_set(errp, ...). error_set() does nothing when passed a null errp. This lets callers ignore errors without fuss. I guess we don't want callers to pass a non-null errp with *errp != NULL ever, but I don't think that's spelled out anywhere. I suspect code is generally unprepared for such usage. Your patch *clears* errors through its errp parameter. I'm not saying it's wrong, I just spooks poor ignorant me. My gut feeling: as soon as we go beyond utterly trivial with errors, it's best to put them in local variables, and error_propagate() to the parameter only at the end. Let's review some usage patterns, in the hope of learning more. /* * Do something on @arg. * On error, set *@errp if @errp isn't null. */ void do_something(Argument *arg, Error **errp); // ignoring errors: do_something(arg, NULL); // checking and handling errors locally: Error *local_err = NULL; do_something(arg, &local_err); if (local_err) { // some prefer error_is_set(local_err) here, // but I think that only muddies the waters // error handling goes here error_free(local_err); } // propagating to caller via parameter Error *errp: Error *local_err = NULL; do_something(arg, &local_err); if (local_err) { // local error handling goes here error_propagate(errp, local_err); } // same, but "simpler" (except it doesn't work): do_something(arg, errp); if (error_is_set(errp)) { // BUG: doesn't work when !errp // local error handling goes here } // same, when no local error handling is wanted: do_something(arg, errp); // but it works only once: do_something(arg1, errp); do_something(arg2, errp); // BUG: trips assert() when both fail // pity Let me stress: beware of error_is_set()! If the argument may or may not be null, the result is *worthless*. If it can't be null, you could just as well test the argument directly. If it must be null, the result is always false. More patterns: // accumulating errors, first error wins Error *err = NULL; while (...) { Error *local_err = NULL: do_something(arg, &local_err); if (local_err) { // local error handling goes here error_propagate(&err, local_err); } } // err contains the first error // need to free or propagate it // same, but "simpler" (except it doesn't work) Error *err = NULL; while (...) { do_something(arg, &err);// BUG: trips assert() on second error if (err) { // BUG: always true after first error // local error handling goes here } } // can omit err when propagating, just replace it by errp: // (works because error_propagate() is designed for this) while (...) { Error *local_err = NULL: do_something(arg, &local_err); if (local_err) { // local error handling goes here error_propagate(errp, local_err); } } // errp contains the first error // accumulating errors, last error wins Error *err = NULL; while (...) { Error *local_err = NULL: do_something(arg, &local_err); if (local_err) { // local error handling goes here // if we do the following often, we should perhaps provide a // function for it, just like error_propagate(), only "last // one wins" instead of "first one wins" if (err) { error_free(err); } err = local_err; } } // err contains the last error // need to free or propagate it // can omit err when propagating, but need to be careful, because // errp may be null: while (...) { Error *local_err = NULL: do_something(arg, &local_err); if (local_err) { // local error handling goes here if (error_is_set(errp)) { // exploits that error_is_set(errp) implies errp != NULL error_free(*errp); *errp = NULL; } error_propagate(errp, local_err); } } Just found a tolerable use of error_is_set(). I'd prefer a function error_clear(errp) to clear through a possibly null errp. Still more patterns: // try a number of args, until one works Error *local_err = NULL; for (arg = first_one(); arg; arg = next_one()) { if (local_err) { error_free(local_err); local_err = NULL; } do_something(arg, &local_err); if (!local_err) { break; // arg worked } // local error handling goes here } if (local_err) { // local error handling goes here // need to free or propagate local_err } else { // arg worked } We can't omit local_err when propagating, because with just errp, we can't test whether do_something() succeeded. With a function that return a value that can be tested: /* * Get @arg's foo. * On success, return foo. * On failure, return null, and set *@errp if @errp isn't null. */ Foo *get_foo(Argument *arg, Error *errp) we can omit local_err: // try a number of args, until one works for (arg = first_one(); arg; arg = next_one()) { if (error_is_set(errp)) { // exploits that error_is_set(errp) implies errp != NULL error_free(*errp); *errp = NULL; } foo = get_foo(arg, errp); if (foo) { break; // arg worked } // local error handling goes here } if (foo) { // arg worked } else { // local error handling goes here // need to free or propagate local_err } This is roughly how your patch works. Functions like get_foo() spook me, because when I do local_err = NULL; foo = get_foo(arg, &local_err); if (!foo) { // fail return; } // success // use foo (surely not null) I worry about local_err being null at // fail, or non-null (and leaked) at // success. When I do local_err = NULL; foo = get_foo(arg, &local_err); if (local_err) { // fail return; } // success // use foo I worry about foo being null at // success, or non-null (and leaked) at // fail. Perhaps I'm too easily worried. ^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2013-03-20 13:52 UTC | newest] Thread overview: 24+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-03-06 10:48 [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure Kevin Wolf 2013-03-06 11:04 ` Paolo Bonzini 2013-03-06 11:11 ` Kevin Wolf 2013-03-06 14:46 ` Laszlo Ersek 2013-03-06 15:04 ` Paolo Bonzini 2013-03-06 15:19 ` Kevin Wolf 2013-03-06 15:38 ` Laszlo Ersek 2013-03-06 15:47 ` Kevin Wolf 2013-03-06 16:04 ` Laszlo Ersek 2013-03-06 15:59 ` Markus Armbruster 2013-03-06 16:43 ` Paolo Bonzini 2013-03-14 14:57 ` [Qemu-devel] [RFC PATCH] qemu-socket: Use local error variable Kevin Wolf 2013-03-14 15:52 ` Laszlo Ersek 2013-03-15 8:37 ` Kevin Wolf 2013-03-15 16:55 ` Laszlo Ersek 2013-03-15 17:55 ` Kevin Wolf 2013-03-15 18:39 ` Laszlo Ersek 2013-03-19 20:34 ` [Qemu-devel] [PATCH] qemu-sockets: Fix assertion failure Luiz Capitulino 2013-03-20 8:39 ` Kevin Wolf 2013-03-20 12:57 ` Luiz Capitulino 2013-03-20 13:37 ` Kevin Wolf 2013-03-20 13:52 ` Luiz Capitulino 2013-03-06 15:05 ` Markus Armbruster 2013-03-06 15:05 ` [Qemu-devel] Error ** parameter conventions (was: [PATCH] qemu-sockets: Fix assertion failure) Markus Armbruster
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).