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

Re: [Xen-devel] [PATCH RFC V2 05/10] libxl_json: introduce parser functions for builtin types



On Tue, Apr 22, 2014 at 04:09:58PM +0100, Ian Campbell wrote:
> Please could you CC Anthony too, I think he wrote all this
> libxl__json_object stuff.
> 
> On Thu, 2014-04-17 at 12:13 +0100, Wei Liu wrote:
> > @@ -396,6 +396,66 @@ out:
> >      return s;
> >  }
> >  
> > +int libxl_cpuid_policy_list_parse_json(libxl_ctx *ctx,
> > +                                       const libxl__json_object *o,
> > +                                       libxl_cpuid_policy_list *p)
> > +{
> > +    int i, size;
> > +    libxl_cpuid_policy_list l;
> > +
> > +    if (!libxl__json_object_is_array(o))
> > +        return -1;
> > +
> > +    if (!o->u.array->count)
> > +        return 0;
> > +
> > +    size = o->u.array->count;
> > +    /* need one extra slot as setinel */
> 
> "sentinel"
> 
> > +    l = *p = calloc(size + 1, sizeof(libxl_cpuid_policy));
> 
> This function should GC_INIT and use the provided gc for allocations,
> shouldn't it?.
> 

I see. You're right here.

> > +
> > +    if (!l)
> > +        return -1;
> > +
> > +    memset(l, 0, sizeof(libxl_cpuid_policy) * (size + 1));
> > +    l[size].input[0] = XEN_CPUID_INPUT_UNUSED;
> > +    l[size].input[1] = XEN_CPUID_INPUT_UNUSED;
> > +
> > +    for (i = 0; i < size; i++) {
> > +        const libxl__json_object *t;
> > +        int j;
> > +
> > +        if (flexarray_get(o->u.array, i, (void**)&t) != 0)
> > +            return -1;          /* dispose_fn will clean up memory
> > +                                 * allocation */
> 
> You haven't done a gc allocation, so it won't. Looking closer I think
> this falls into case #1 of the comment in libxl.h, which means the
> allocation should have come from the heap, but that means you need to
> manually free it.
> 

The aformentioned "calloc" falls into #1 but not this one.

My comment is a bit confusing. The comment here actually refers to all
the malloc'ed memory in the loop, which will be freed by
libxl_cpuid_dispose.

In any case I will check other occurences of this.

> (I see this comment about dispose_fn a lot, so I won't repeat it)
> 
> > +        for (j = 0; j < 4; j++) {
> 
> This, and the code it is based on, really ought to use ARRAY_SIZE I
> think.
> 

Ack.

> > +            const libxl__json_object *r;
> > +
> > +            r = libxl__json_map_get(policy_names[j], t, JSON_STRING);
> > +            if (!r)
> > +                l[i].policy[j] = NULL;
> > +            else
> > +                l[i].policy[j] = strdup(r->u.string);
> > +        }
> > +    }
> > +
> > +    assert(i == size);
> 
> Given a lack of break's in the for loop this seems overly defensive to
> me.
> 

I will remove this.

> > +
> > +    return 0;
> > +}
> > +
> >  /*
> >   * Local variables:
> >   * mode: C
> > diff --git a/tools/libxl/libxl_json.c b/tools/libxl/libxl_json.c
> > index 6f1116f..e2d5dbe 100644
> > --- a/tools/libxl/libxl_json.c
> > +++ b/tools/libxl/libxl_json.c
> > @@ -100,6 +100,35 @@ yajl_gen_status libxl_defbool_gen_json(yajl_gen hand,
> >      return libxl__yajl_gen_asciiz(hand, libxl_defbool_to_string(*db));
> >  }
> >  
> > +int libxl_defbool_parse_json(libxl_ctx *ctx, const libxl__json_object *o,
> > +                             libxl_defbool *p)
> > +{
> > +    if (!libxl__json_object_is_string(o))
> > +        return -1;
> > +
> > +    if (!strncmp(o->u.string, "<default>", strlen("<default>")))
> > +        p->val = 0;
> > +    else if (!strncmp(o->u.string, "True", strlen("True")))
> > +        p->val = 1;
> > +    else if (!strncmp(o->u.string, "False", strlen("False")))
> 
> Should have some internal #defines for these strings and use in the
> generator too. Also you should use LIBXL__DEFBOOL_DEFAULT and friends.
> 

Ack.

> > @@ -128,6 +166,34 @@ out:
> >      return s;
> >  }
> >  
> > +int libxl_bitmap_parse_json(libxl_ctx *ctx, const libxl__json_object *o,
> > +                            libxl_bitmap *p)
> > +{
> > +    int i;
> > +    int size;
> > +    const libxl__json_object *t;
> > +
> > +    if (!libxl__json_object_is_array(o))
> > +        return -1;
> > +
> > +    if (!o->u.array->count)
> > +        return 0;
> > +
> > +    t = libxl__json_array_get(o, o->u.array->count - 1);
> > +    size = t->u.i + 1;
> 
> What is this doing? It's retrieving the last item in the array, assuming
> it is an integer and then inferring the length of the array from it?
> 

Yes.

> Oh this is because a bitmask is represented as an array which contains a
> list of the bit indexes which are true.
> 
> Is the json array guaranteed to be sorted? I guess it is if libxl
> generated it, but can we rely on that?
> 

Yes. I basically reverse-engineer the process to generate the array and
find out that it's sorted.

> I wonder if it is too late to change the json representation of a
> bitmask that we are using. Thoughts?
> 

Probably yes. It's a public function in libxl API so I wouldn't be
surprised if some high level tool depends on it.

> > +
> > +    libxl_bitmap_alloc(ctx, p, size);
> > +
> > +    for (i = 0; (t = libxl__json_array_get(o, i)); i++) {
> > +        if (!libxl__json_object_is_integer(t))
> > +            return -1;          /* dispose_fn will clean up memory
> > +                                 * allocation */
> > +        libxl_bitmap_set(p, t->u.i);
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> >  yajl_gen_status libxl_key_value_list_gen_json(yajl_gen hand,
> >                                                libxl_key_value_list *pkvl)
> >  {
> > @@ -155,6 +221,43 @@ out:
> >      return s;
> >  }
> >  
> > +int libxl_key_value_list_parse_json(libxl_ctx *ctx, const 
> > libxl__json_object *o,
> > +                                    libxl_key_value_list *p)
> > +{
> > +    libxl__json_map_node *node = NULL;
> > +    flexarray_t *maps = NULL;
> > +    int i, size;
> > +    libxl_key_value_list kvl;
> > +
> > +    if (!libxl__json_object_is_map(o))
> > +        return -1;
> > +
> > +    maps = o->u.map;
> > +    size = maps->count * 2;
> > +    kvl = *p = calloc(size, sizeof(char *));
> > +    if (!kvl)
> > +        return -1;
> > +
> > +    memset(kvl, 0, sizeof(char *) * size);
> > +
> > +    for (i = 0; i < maps->count; i++) {
> > +        int idx = i * 2;
> > +        if (flexarray_get(maps, i, (void**)&node) != 0)
> > +            return -1;
> > +        assert(libxl__json_object_is_string(node->obj) ||
> > +               libxl__json_object_is_null(node->obj));
> 
> I think we may need to be mindful of potentially malicious json code
> which a toolstack is feeding to these parser functions, don't we?
> 
> IOW asserting and crashing the entire daemon would be unfortunate.
> 

I think "return -1" will be more appropriate in this case.

> > +        kvl[idx]   = strdup(node->map_key);
> > +        if (libxl__json_object_is_string(node->obj))
> > +            kvl[idx+1] = strdup(node->obj->u.string);
> > +        else
> > +            kvl[idx+1] = NULL;
> > +    }
> > +
> > +    assert(i == maps->count);
> 
> Too defensive again.
> 

Ack.

> > +
> > +    return 0;
> > +}
> > +
> >  yajl_gen_status libxl_string_list_gen_json(yajl_gen hand, 
> > libxl_string_list *pl)
> >  {
> >      libxl_string_list l = *pl;
> > @@ -201,6 +343,27 @@ out:
> >      return s;
> >  }
> >  
> > +int libxl_hwcap_parse_json(libxl_ctx *ctx, const libxl__json_object *o,
> > +                           libxl_hwcap *p)
> > +{
> > +    int i;
> > +
> > +    if (!libxl__json_object_is_array(o))
> > +        return -1;
> 
> I jut noticed the error handling here, but I'm sure it was the same for
> all the preceding. libxl functions should return an ERROR_* code and not
> -1 unless you have a good reason not to.
> 

OK. Will change to that.

Wei.

> Ian.

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.