qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v6 02/23] qapi: Require int64/uint64 implementat


From: Markus Armbruster
Subject: Re: [Qemu-devel] [PATCH v6 02/23] qapi: Require int64/uint64 implementation
Date: Thu, 03 Dec 2015 09:30:24 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux)

Eric Blake <address@hidden> writes:

> On 11/27/2015 05:05 AM, Markus Armbruster wrote:
>> Eric Blake <address@hidden> writes:
>> 
>>> Now that all visitors supply both type_int64() and type_uint64()
>>> callbacks, we can drop the redundant type_int() callback (the
>>> public interface visit_type_int() remains, but calls into
>>> type_int64() under the hood).
>>>
>>> Signed-off-by: Eric Blake <address@hidden>
>>>
>
>>>  void visit_type_uint8(Visitor *v, uint8_t *obj, const char *name, Error 
>>> **errp)
>>>  {
>>> -    int64_t value;
>>> +    uint64_t value;
>>>
>>>      if (v->type_uint8) {
>>>          v->type_uint8(v, obj, name, errp);
>>>      } else {
>>>          value = *obj;
>>> -        v->type_int(v, &value, name, errp);
>>> -        if (value < 0 || value > UINT8_MAX) {
>>> +        v->type_uint64(v, &value, name, errp);
>>> +        if (value > UINT8_MAX) {
>>>              error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
>>>                         name ? name : "null", "uint8_t");
>>>              return;
>> 
>> Note that this relies on value being in range after type_uint64() fails.
>> If it isn't, we call error_setg() with non-null *errp.
>> 
>> Two solutions:
>> 
>> 1. Stipulate that type_uint64() & friends leave value alone on error.
>>    Works, because its initial value *obj is in range.
>
> Pre-existing and simpler, but sets a poor example for the rest of the
> code base (not everyone is going to read the fine print for why it works
> here), and requires cross-file audits to ensure visitors comply.

Yes, but "don't mess up externally visible state on error" is a pretty
common design maxim.

>> 2. Avoid using value on error.  A clean way to do this:
>> 
>>         Error *err = NULL;
>> 
>>         value = *obj;
>>         v->type_uint64(v, &value, name, &err);
>>         if (err) {
>>             error_propagate(errp, err);
>>             return;
>>         }
>>         if (value < 0 || value > UINT8_MAX) {
>>             error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
>>                        name ? name : "null", "uint8_t");
>>             return;
>>         }
>>         *obj = value;
>> 
>>    More boilerplate.  If we pick this solution, we'll want a separate
>>    PATCH 1.5 cleaning up the preexisting instances.
>
> Of course, if I do the cleanup as 1.5, then patch 3/23 reindents
> everything, that's a lot of churn.  So I may end up rearranging 2 and 3
> after all, and then do the cleanup as 3.5.
>
> Or maybe option 3, write a pair of helper functions containing the
> boilerplate for checking against min and max:
>
> void visit_type_intN(Visitor *v, int64_t *obj, const char *name,
>                      int64_t min, int64_t max, Error **errp);
> void visit_type_uintN(Visitor *v, int64_t *obj, const char *name,
>                       uint64_t max, Error **errp);
>
> leaving us with simpler clients:
>
> visit_type_int8(Visitor *v, int8_t *obj, const char *name, Error **errp)
> {
>     int64_t value = *obj;
>     visit_type_uintN(v, &value, name, INT8_MIN, INT8_MAX, errp);
>     *obj = value;
> }
>
> and here, because the helpers are in the same file, it's easier to prove
> that value was unchanged on error.  Or I may even squash 2 and 3 into a
> single patch now.

Artistic license applies.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]