qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH v4 05/22] qobject: Simplify qobject_from_jsonv()


From: Eric Blake
Subject: Re: [Qemu-devel] [PATCH v4 05/22] qobject: Simplify qobject_from_jsonv()
Date: Mon, 2 Oct 2017 09:30:04 -0500
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.3.0

On 10/02/2017 12:46 AM, Markus Armbruster wrote:

>>>> +    /*
>>>> +     * This seemingly unnecessary copy is required in case va_list
>>>> +     * is an array type.
>>>> +     */
>>>
>>> --verbose?
>>>
>>>> +    va_copy(ap_copy, ap);
>>>> +    obj = qobject_from_json_internal(string, &ap_copy, &error_abort);
>>>> +    va_end(ap_copy);
>>
>> Code motion. But if the comment needs to be more verbose in the
>> destination than it was on the source, the rationale is that C99/POSIX
>> allows 'typedef something va_list[]' (that is, where va_list is an array
>> of some other type), although I don't know of any modern OS that
>> actually defines it like that.  Based on C pointer-decay rules, '&ap'
>> has a different type based on whether va_list was a struct/pointer or an
>> array type, when 'va_list ap' was passed as a parameter; so we can't
>> portably use qobject_from_json_internal(string, &ap, &error_abort).  The
>> va_copy() is what lets us guarantee that &ap_list is a pointer to a
>> va_list regardless of the type of va_list (because va_copy was declared
>> locally, rather than in a parameter list, and is therefore not subject
>> to pointer decay), and NOT an accidental pointer to first element of the
>> va_list array on platforms where va_list is an array.
> 
> I'm dense this Monday morning --- I still can't see where exactly
> passing &ap directly goes wrong.
> 
> Two cases:
> 
> 1. va_list is a typedef name for a non-array type T.
> 
> 2. va_list is a typedef name for an array type E[].
> 
> What are the types of actual argument &ap and formal parameter va_list
> *ap in either case?
> 
> How exactly does case 2 break?

An example program is probably the best to visualize the problem:

$ cat typefun.c
#include <stdio.h>

typedef struct T {
    int i[5];
} T;
typedef struct E {
    int i;
} E;

typedef T list1;
typedef E list2[5];

void bar(const char *prefix, list1 *l1, list2 *l2) {
    printf ("%s: %zu %zu\n", prefix, sizeof(&l1), sizeof(&l2));
}

void foo(list1 l1, list2 l2) {
    printf ("parameter sizes: %zu %zu\n", sizeof(l1), sizeof(l2));
    bar("called with address of parameter", &l1, &l2);
}

int main(void) {
    list1 l1;
    list2 l2;
    printf ("local variable sizes: %zu %zu\n", sizeof(l1), sizeof(l2));
    bar("called with address of local variable", &l1, &l2);
    foo(l1, l2);
    return 0;
}

$ gcc -o typefun -Wall typefun.c
typefun.c: In function ‘foo’:
typefun.c:18:61: warning: ‘sizeof’ on array function parameter ‘l2’ will
return size of ‘E * {aka struct E *}’ [-Wsizeof-array-argument]
     printf ("parameter sizes: %zu %zu\n", sizeof(l1), sizeof(l2));
                                                             ^
typefun.c:17:26: note: declared here
 void foo(list1 l1, list2 l2) {
                          ^~
typefun.c:19:50: warning: passing argument 3 of ‘bar’ from incompatible
pointer type [-Wincompatible-pointer-types]
     bar("called with address of parameter", &l1, &l2);
                                                  ^
typefun.c:13:6: note: expected ‘E (*)[5] {aka struct E (*)[5]}’ but
argument is of type ‘E ** {aka struct E **}’
 void bar(const char *prefix, list1 *l1, list2 *l2) {
      ^~~

$ ./typefun
local variable sizes: 20 20
called with address of local variable: 8 8
parameter sizes: 20 8
called with address of parameter: 8 8

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

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