[sheepdog] [RFC v5 024/126] error: auto propagated local_err
Markus Armbruster
armbru at redhat.com
Fri Dec 6 09:13:57 CET 2019
Vladimir Sementsov-Ogievskiy <vsementsov at virtuozzo.com> writes:
> 05.12.2019 17:58, Vladimir Sementsov-Ogievskiy wrote:
>> 05.12.2019 15:36, Markus Armbruster wrote:
>>> Vladimir Sementsov-Ogievskiy <vsementsov at virtuozzo.com> writes:
>>>
>>>> 04.12.2019 17:59, Markus Armbruster wrote:
>>>>> Vladimir Sementsov-Ogievskiy <vsementsov at virtuozzo.com> writes:
>>>>>
>>>>>> Here is introduced ERRP_AUTO_PROPAGATE macro, to be used at start of
>>>>>> functions with errp OUT parameter.
>>>>>>
>>>>>> It has three goals:
>>>>>>
>>>>>> 1. Fix issue with error_fatal & error_prepend/error_append_hint: user
>>>>>> can't see this additional information, because exit() happens in
>>>>>> error_setg earlier than information is added. [Reported by Greg Kurz]
>>>>>>
>>>>>> 2. Fix issue with error_abort & error_propagate: when we wrap
>>>>>> error_abort by local_err+error_propagate, resulting coredump will
>>>>>> refer to error_propagate and not to the place where error happened.
>>>>>
>>>>> I get what you mean, but I have plenty of context.
>>>>>
>>>>>> (the macro itself doesn't fix the issue, but it allows to [3.] drop all
>>>>>> local_err+error_propagate pattern, which will definitely fix the issue)
>>>>>
>>>>> The parenthesis is not part of the goal.
>>>>>
>>>>>> [Reported by Kevin Wolf]
>>>>>>
>>>>>> 3. Drop local_err+error_propagate pattern, which is used to workaround
>>>>>> void functions with errp parameter, when caller wants to know resulting
>>>>>> status. (Note: actually these functions could be merely updated to
>>>>>> return int error code).
>>>>>>
>>>>>> To achieve these goals, we need to add invocation of the macro at start
>>>>>> of functions, which needs error_prepend/error_append_hint (1.); add
>>>>>> invocation of the macro at start of functions which do
>>>>>> local_err+error_propagate scenario the check errors, drop local errors
>>>>>> from them and just use *errp instead (2., 3.).
>>>>>
>>>>> The paragraph talks about two cases: 1. and 2.+3.
>>>>
>>>> Hmm, I don't think so.. 1. and 2. are issues. 3. is a refactoring.. We just
>>>> fix achieve 2 and 3 by one action.
>>>>
>>>>> Makes me think we
>>>>> want two paragraphs, each illustrated with an example.
>>>>>
>>>>> What about you provide the examples, and then I try to polish the prose?
>>>>
>>>> 1: error_fatal problem
>>>>
>>>> Assume the following code flow:
>>>>
>>>> int f1(errp) {
>>>> ...
>>>> ret = f2(errp);
>>>> if (ret < 0) {
>>>> error_append_hint(errp, "very useful hint");
>>>> return ret;
>>>> }
>>>> ...
>>>> }
>>>>
>>>> Now, if we call f1 with &error_fatal argument and f2 fails, the program
>>>> will exit immediately inside f2, when setting the errp. User will not
>>>> see the hint.
>>>>
>>>> So, in this case we should use local_err.
>>>
>>> How does this example look after the transformation?
>>
>> Good point.
>>
>> int f1(errp) {
>> ERRP_AUTO_PROPAGATE();
>> ...
>> ret = f2(errp);
>> if (ret < 0) {
>> error_append_hint(errp, "very useful hint");
>> return ret;
>> }
>> ...
>> }
>>
>> - nothing changed, only add macro at start. But now errp is safe, if it was
>> error_fatal it is wrapped by local error, and will only call exit on automatic
>> propagation on f1 finish.
>>
>>>
>>>> 2: error_abort problem
>>>>
>>>> Now, consider functions without return value. We normally use local_err
>>>> variable to catch failures:
>>>>
>>>> void f1(errp) {
>>>> Error *local_err = NULL;
>>>> ...
>>>> f2(&local_err);
>>>> if (local_err) {
>>>> error_propagate(errp, local_err);
>>>> return;
>>>> }
>>>> ...
>>>> }
>>>>
>>>> Now, if we call f2 with &error_abort and f2 fails, the stack in resulting
>>>> crash dump will point to error_propagate, not to the failure point in f2,
>>>> which complicates debugging.
>>>>
>>>> So, we should never wrap error_abort by local_err.
>>>
>>> Likewise.
>>
>> And here:
>>
>> void f1(errp) {
>> ERRP_AUTO_PROPAGATE();
>> ...
>> f2(errp);
>> if (*errp) {
>> return;
>> }
>> ...
>>
>> - if errp was NULL, it is wrapped, so dereferencing errp is safe. On return,
>> local error is automatically propagated to original one.
>
> and if it was error_abort, it is not wrapped, so will crash where failed.
We still need to avoid passing on unwrapped @errp when we want to ignore
some errors, as in fit_load_fdt(), but that should be quite rare.
Doesn't invalidate your approach.
[...]
More information about the sheepdog
mailing list