diff mbox series

[for-4.1?,2/2] vmstate.h: Type check VMSTATE_STRUCT_VARRAY macros

Message ID 20190725163710.11703-3-peter.maydell@linaro.org
State Superseded
Headers show
Series Typecheck VMSTATE VARRAY macros and fix bug found | expand

Commit Message

Peter Maydell July 25, 2019, 4:37 p.m. UTC
The VMSTATE_STRUCT_VARRAY_UINT32 macro is intended to handle
migrating a field which is an array of structs, but where instead of
migrating the entire array we only migrate a variable number of
elements of it.

The VMSTATE_STRUCT_VARRAY_POINTER_UINT32 macro is intended to handle
migrating a field which is of pointer type, and points to a
dynamically allocated array of structs of variable size.

We weren't actually checking that the field passed to
VMSTATE_STRUCT_VARRAY_UINT32 really is an array, with the result that
accidentally using it where the _POINTER_ macro was intended would
compile but silently corrupt memory on migration.

Add type-checking that enforces that the field passed in is
really of the right array type. This applies to all the VMSTATE
macros which use flags including VMS_VARRAY_* but not VMS_POINTER.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

---
 include/migration/vmstate.h | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

-- 
2.20.1

Comments

Dr. David Alan Gilbert July 25, 2019, 5:27 p.m. UTC | #1
* Peter Maydell (peter.maydell@linaro.org) wrote:
> The VMSTATE_STRUCT_VARRAY_UINT32 macro is intended to handle

> migrating a field which is an array of structs, but where instead of

> migrating the entire array we only migrate a variable number of

> elements of it.

> 

> The VMSTATE_STRUCT_VARRAY_POINTER_UINT32 macro is intended to handle

> migrating a field which is of pointer type, and points to a

> dynamically allocated array of structs of variable size.

> 

> We weren't actually checking that the field passed to

> VMSTATE_STRUCT_VARRAY_UINT32 really is an array, with the result that

> accidentally using it where the _POINTER_ macro was intended would

> compile but silently corrupt memory on migration.

> 

> Add type-checking that enforces that the field passed in is

> really of the right array type. This applies to all the VMSTATE

> macros which use flags including VMS_VARRAY_* but not VMS_POINTER.

> 

> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>


> ---

>  include/migration/vmstate.h | 27 +++++++++++++++++++++------

>  1 file changed, 21 insertions(+), 6 deletions(-)

> 

> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h

> index ca68584eba4..2df333c3612 100644

> --- a/include/migration/vmstate.h

> +++ b/include/migration/vmstate.h

> @@ -227,8 +227,19 @@ extern const VMStateInfo vmstate_info_bitmap;

>  extern const VMStateInfo vmstate_info_qtailq;

>  

>  #define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)

> +/* Check that t2 is an array of t1 of size n */

>  #define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)


I'd have to admit I don't understand why that does what you say;
I'd expected something to index a t2 pointer with [n].

However, for the rest of it, from migration I'm happy:

Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>


given it's just fixing an ARM bug, and given it'll blow up straight away
I think it's OK for 4.1; the only risk is if we find a compiler we don't
like.


>  #define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)

> +/*

> + * type of element 0 of the specified (array) field of the type.

> + * Note that if the field is a pointer then this will return the

> + * pointed-to type rather than complaining.

> + */

> +#define typeof_elt_of_field(type, field) typeof(((type *)0)->field[0])

> +/* Check that field f in struct type t2 is an array of t1, of any size */

> +#define type_check_varray(t1, t2, f)                                 \

> +    (type_check(t1, typeof_elt_of_field(t2, f))                      \

> +     + QEMU_BUILD_BUG_ON_ZERO(!QEMU_IS_ARRAY(((t2 *)0)->f)))

>  

>  #define vmstate_offset_value(_state, _field, _type)                  \

>      (offsetof(_state, _field) +                                      \

> @@ -253,6 +264,10 @@ extern const VMStateInfo vmstate_info_qtailq;

>      vmstate_offset_array(_state, _field, uint8_t,                    \

>                           sizeof(typeof_field(_state, _field)))

>  

> +#define vmstate_offset_varray(_state, _field, _type)                 \

> +    (offsetof(_state, _field) +                                      \

> +     type_check_varray(_type, _state, _field))

> +

>  /* In the macros below, if there is a _version, that means the macro's

>   * field will be processed only if the version being received is >=

>   * the _version specified.  In general, if you add a new field, you

> @@ -347,7 +362,7 @@ extern const VMStateInfo vmstate_info_qtailq;

>      .info       = &(_info),                                          \

>      .size       = sizeof(_type),                                     \

>      .flags      = VMS_VARRAY_UINT32|VMS_MULTIPLY_ELEMENTS,           \

> -    .offset     = offsetof(_state, _field),                          \

> +    .offset     = vmstate_offset_varray(_state, _field, _type),      \

>  }

>  

>  #define VMSTATE_ARRAY_TEST(_field, _state, _num, _test, _info, _type) {\

> @@ -376,7 +391,7 @@ extern const VMStateInfo vmstate_info_qtailq;

>      .info       = &(_info),                                          \

>      .size       = sizeof(_type),                                     \

>      .flags      = VMS_VARRAY_INT32,                                  \

> -    .offset     = offsetof(_state, _field),                          \

> +    .offset     = vmstate_offset_varray(_state, _field, _type),      \

>  }

>  

>  #define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\

> @@ -416,7 +431,7 @@ extern const VMStateInfo vmstate_info_qtailq;

>      .info       = &(_info),                                          \

>      .size       = sizeof(_type),                                     \

>      .flags      = VMS_VARRAY_UINT16,                                 \

> -    .offset     = offsetof(_state, _field),                          \

> +    .offset     = vmstate_offset_varray(_state, _field, _type),      \

>  }

>  

>  #define VMSTATE_VSTRUCT_TEST(_field, _state, _test, _version, _vmsd, _type, _struct_version) { \

> @@ -520,7 +535,7 @@ extern const VMStateInfo vmstate_info_qtailq;

>      .vmsd       = &(_vmsd),                                          \

>      .size       = sizeof(_type),                                     \

>      .flags      = VMS_STRUCT|VMS_VARRAY_UINT8,                       \

> -    .offset     = offsetof(_state, _field),                          \

> +    .offset     = vmstate_offset_varray(_state, _field, _type),      \

>  }

>  

>  /* a variable length array (i.e. _type *_field) but we know the

> @@ -573,7 +588,7 @@ extern const VMStateInfo vmstate_info_qtailq;

>      .vmsd       = &(_vmsd),                                          \

>      .size       = sizeof(_type),                                     \

>      .flags      = VMS_STRUCT|VMS_VARRAY_INT32,                       \

> -    .offset     = offsetof(_state, _field),                          \

> +    .offset     = vmstate_offset_varray(_state, _field, _type),      \

>  }

>  

>  #define VMSTATE_STRUCT_VARRAY_UINT32(_field, _state, _field_num, _version, _vmsd, _type) { \

> @@ -583,7 +598,7 @@ extern const VMStateInfo vmstate_info_qtailq;

>      .vmsd       = &(_vmsd),                                          \

>      .size       = sizeof(_type),                                     \

>      .flags      = VMS_STRUCT|VMS_VARRAY_UINT32,                      \

> -    .offset     = offsetof(_state, _field),                          \

> +    .offset     = vmstate_offset_varray(_state, _field, _type),      \

>  }

>  

>  #define VMSTATE_STRUCT_VARRAY_ALLOC(_field, _state, _field_num, _version, _vmsd, _type) {\

> -- 

> 2.20.1

> 

--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
Peter Maydell July 25, 2019, 5:57 p.m. UTC | #2
On Thu, 25 Jul 2019 at 18:27, Dr. David Alan Gilbert
<dgilbert@redhat.com> wrote:
>

> * Peter Maydell (peter.maydell@linaro.org) wrote:

> > The VMSTATE_STRUCT_VARRAY_UINT32 macro is intended to handle

> > migrating a field which is an array of structs, but where instead of

> > migrating the entire array we only migrate a variable number of

> > elements of it.

> >

> > The VMSTATE_STRUCT_VARRAY_POINTER_UINT32 macro is intended to handle

> > migrating a field which is of pointer type, and points to a

> > dynamically allocated array of structs of variable size.

> >

> > We weren't actually checking that the field passed to

> > VMSTATE_STRUCT_VARRAY_UINT32 really is an array, with the result that

> > accidentally using it where the _POINTER_ macro was intended would

> > compile but silently corrupt memory on migration.

> >

> > Add type-checking that enforces that the field passed in is

> > really of the right array type. This applies to all the VMSTATE

> > macros which use flags including VMS_VARRAY_* but not VMS_POINTER.

> >

> > Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

>

> > ---

> >  include/migration/vmstate.h | 27 +++++++++++++++++++++------

> >  1 file changed, 21 insertions(+), 6 deletions(-)

> >

> > diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h

> > index ca68584eba4..2df333c3612 100644

> > --- a/include/migration/vmstate.h

> > +++ b/include/migration/vmstate.h

> > @@ -227,8 +227,19 @@ extern const VMStateInfo vmstate_info_bitmap;

> >  extern const VMStateInfo vmstate_info_qtailq;

> >

> >  #define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)

> > +/* Check that t2 is an array of t1 of size n */

> >  #define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)

>

> I'd have to admit I don't understand why that does what you say;

> I'd expected something to index a t2 pointer with [n].


Note that this is just a comment describing what the existing
macro does, as a way to distinguish its job from that of the
new macro I'm adding.

What happens here is that t2 is a type like "foo [32]", ie
it is an array type already. t1 is the base 'foo' type; so the macro
is checking that t1[n] matches t2, where n is passed in to us
and must match the declared array size of the field (32 in
my example). (In C the size of the array is carried around as
part of its type, and must match on both sides of the expression;
so if you pass in the name of an array field that's the wrong size the
type check will fail, which is what we want.)

> However, for the rest of it, from migration I'm happy:

>

> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

>

> given it's just fixing an ARM bug, and given it'll blow up straight away

> I think it's OK for 4.1; the only risk is if we find a compiler we don't

> like.


thanks
-- PMM
Dr. David Alan Gilbert July 25, 2019, 6 p.m. UTC | #3
* Peter Maydell (peter.maydell@linaro.org) wrote:
> On Thu, 25 Jul 2019 at 18:27, Dr. David Alan Gilbert

> <dgilbert@redhat.com> wrote:

> >

> > * Peter Maydell (peter.maydell@linaro.org) wrote:

> > > The VMSTATE_STRUCT_VARRAY_UINT32 macro is intended to handle

> > > migrating a field which is an array of structs, but where instead of

> > > migrating the entire array we only migrate a variable number of

> > > elements of it.

> > >

> > > The VMSTATE_STRUCT_VARRAY_POINTER_UINT32 macro is intended to handle

> > > migrating a field which is of pointer type, and points to a

> > > dynamically allocated array of structs of variable size.

> > >

> > > We weren't actually checking that the field passed to

> > > VMSTATE_STRUCT_VARRAY_UINT32 really is an array, with the result that

> > > accidentally using it where the _POINTER_ macro was intended would

> > > compile but silently corrupt memory on migration.

> > >

> > > Add type-checking that enforces that the field passed in is

> > > really of the right array type. This applies to all the VMSTATE

> > > macros which use flags including VMS_VARRAY_* but not VMS_POINTER.

> > >

> > > Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

> >

> > > ---

> > >  include/migration/vmstate.h | 27 +++++++++++++++++++++------

> > >  1 file changed, 21 insertions(+), 6 deletions(-)

> > >

> > > diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h

> > > index ca68584eba4..2df333c3612 100644

> > > --- a/include/migration/vmstate.h

> > > +++ b/include/migration/vmstate.h

> > > @@ -227,8 +227,19 @@ extern const VMStateInfo vmstate_info_bitmap;

> > >  extern const VMStateInfo vmstate_info_qtailq;

> > >

> > >  #define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)

> > > +/* Check that t2 is an array of t1 of size n */

> > >  #define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)

> >

> > I'd have to admit I don't understand why that does what you say;

> > I'd expected something to index a t2 pointer with [n].

> 

> Note that this is just a comment describing what the existing

> macro does, as a way to distinguish its job from that of the

> new macro I'm adding.

> 

> What happens here is that t2 is a type like "foo [32]", ie

> it is an array type already. t1 is the base 'foo' type; so the macro

> is checking that t1[n] matches t2, where n is passed in to us

> and must match the declared array size of the field (32 in

> my example). (In C the size of the array is carried around as

> part of its type, and must match on both sides of the expression;

> so if you pass in the name of an array field that's the wrong size the

> type check will fail, which is what we want.)


Ah, OK that makes sense; what it really needs is that example to make
me realise that t2 was already the array.

Dave

> > However, for the rest of it, from migration I'm happy:

> >

> > Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> >

> > given it's just fixing an ARM bug, and given it'll blow up straight away

> > I think it's OK for 4.1; the only risk is if we find a compiler we don't

> > like.

> 

> thanks

> -- PMM

--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
Damien Hedde July 26, 2019, 9:12 a.m. UTC | #4
On 7/25/19 7:27 PM, Dr. David Alan Gilbert wrote:
> * Peter Maydell (peter.maydell@linaro.org) wrote:

>> The VMSTATE_STRUCT_VARRAY_UINT32 macro is intended to handle

>> migrating a field which is an array of structs, but where instead of

>> migrating the entire array we only migrate a variable number of

>> elements of it.

>>

>> The VMSTATE_STRUCT_VARRAY_POINTER_UINT32 macro is intended to handle

>> migrating a field which is of pointer type, and points to a

>> dynamically allocated array of structs of variable size.

>>

>> We weren't actually checking that the field passed to

>> VMSTATE_STRUCT_VARRAY_UINT32 really is an array, with the result that

>> accidentally using it where the _POINTER_ macro was intended would

>> compile but silently corrupt memory on migration.

>>

>> Add type-checking that enforces that the field passed in is

>> really of the right array type. This applies to all the VMSTATE

>> macros which use flags including VMS_VARRAY_* but not VMS_POINTER.

>>

>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

> 

> However, for the rest of it, from migration I'm happy:

> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

> 


Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>

Tested-by: Damien Hedde <damien.hedde@greensocs.com>


Damien
Peter Maydell July 26, 2019, 9:24 a.m. UTC | #5
On Thu, 25 Jul 2019 at 19:00, Dr. David Alan Gilbert
<dgilbert@redhat.com> wrote:
>

> * Peter Maydell (peter.maydell@linaro.org) wrote:

> > On Thu, 25 Jul 2019 at 18:27, Dr. David Alan Gilbert

> > <dgilbert@redhat.com> wrote:

> > >

> > > * Peter Maydell (peter.maydell@linaro.org) wrote:

> > > >  #define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)

> > > > +/* Check that t2 is an array of t1 of size n */

> > > >  #define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)

> > >

> > > I'd have to admit I don't understand why that does what you say;

> > > I'd expected something to index a t2 pointer with [n].

> >

> > Note that this is just a comment describing what the existing

> > macro does, as a way to distinguish its job from that of the

> > new macro I'm adding.

> >

> > What happens here is that t2 is a type like "foo [32]", ie

> > it is an array type already. t1 is the base 'foo' type; so the macro

> > is checking that t1[n] matches t2, where n is passed in to us

> > and must match the declared array size of the field (32 in

> > my example). (In C the size of the array is carried around as

> > part of its type, and must match on both sides of the expression;

> > so if you pass in the name of an array field that's the wrong size the

> > type check will fail, which is what we want.)

>

> Ah, OK that makes sense; what it really needs is that example to make

> me realise that t2 was already the array.


Would

/*
 * Check that type t2 is an array of type t1 of size n,
 * eg if t1 is 'foo' and n is 32 then t2 must be 'foo[32]'
 */

be clearer ?

thanks
-- PMM
Dr. David Alan Gilbert July 26, 2019, 9:32 a.m. UTC | #6
* Peter Maydell (peter.maydell@linaro.org) wrote:
> On Thu, 25 Jul 2019 at 19:00, Dr. David Alan Gilbert

> <dgilbert@redhat.com> wrote:

> >

> > * Peter Maydell (peter.maydell@linaro.org) wrote:

> > > On Thu, 25 Jul 2019 at 18:27, Dr. David Alan Gilbert

> > > <dgilbert@redhat.com> wrote:

> > > >

> > > > * Peter Maydell (peter.maydell@linaro.org) wrote:

> > > > >  #define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)

> > > > > +/* Check that t2 is an array of t1 of size n */

> > > > >  #define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)

> > > >

> > > > I'd have to admit I don't understand why that does what you say;

> > > > I'd expected something to index a t2 pointer with [n].

> > >

> > > Note that this is just a comment describing what the existing

> > > macro does, as a way to distinguish its job from that of the

> > > new macro I'm adding.

> > >

> > > What happens here is that t2 is a type like "foo [32]", ie

> > > it is an array type already. t1 is the base 'foo' type; so the macro

> > > is checking that t1[n] matches t2, where n is passed in to us

> > > and must match the declared array size of the field (32 in

> > > my example). (In C the size of the array is carried around as

> > > part of its type, and must match on both sides of the expression;

> > > so if you pass in the name of an array field that's the wrong size the

> > > type check will fail, which is what we want.)

> >

> > Ah, OK that makes sense; what it really needs is that example to make

> > me realise that t2 was already the array.

> 

> Would

> 

> /*

>  * Check that type t2 is an array of type t1 of size n,

>  * eg if t1 is 'foo' and n is 32 then t2 must be 'foo[32]'

>  */

> 

> be clearer ?


Yep.

Dave

> thanks

> -- PMM

--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
Peter Maydell July 26, 2019, 9:33 a.m. UTC | #7
On Fri, 26 Jul 2019 at 10:32, Dr. David Alan Gilbert
<dgilbert@redhat.com> wrote:
>

> * Peter Maydell (peter.maydell@linaro.org) wrote:

> > Would

> >

> > /*

> >  * Check that type t2 is an array of type t1 of size n,

> >  * eg if t1 is 'foo' and n is 32 then t2 must be 'foo[32]'

> >  */

> >

> > be clearer ?

>

> Yep.


OK, I'll fold that in. Are you happy for me to take this
via the target-arm tree for 4.1, given the two dependent
patches are both for arm devices?

thanks
-- PMM
Dr. David Alan Gilbert July 26, 2019, 9:34 a.m. UTC | #8
* Peter Maydell (peter.maydell@linaro.org) wrote:
> On Fri, 26 Jul 2019 at 10:32, Dr. David Alan Gilbert

> <dgilbert@redhat.com> wrote:

> >

> > * Peter Maydell (peter.maydell@linaro.org) wrote:

> > > Would

> > >

> > > /*

> > >  * Check that type t2 is an array of type t1 of size n,

> > >  * eg if t1 is 'foo' and n is 32 then t2 must be 'foo[32]'

> > >  */

> > >

> > > be clearer ?

> >

> > Yep.

> 

> OK, I'll fold that in. Are you happy for me to take this

> via the target-arm tree for 4.1, given the two dependent

> patches are both for arm devices?


Yep

> thanks

> -- PMM

--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
diff mbox series

Patch

diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index ca68584eba4..2df333c3612 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -227,8 +227,19 @@  extern const VMStateInfo vmstate_info_bitmap;
 extern const VMStateInfo vmstate_info_qtailq;
 
 #define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)
+/* Check that t2 is an array of t1 of size n */
 #define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
 #define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)
+/*
+ * type of element 0 of the specified (array) field of the type.
+ * Note that if the field is a pointer then this will return the
+ * pointed-to type rather than complaining.
+ */
+#define typeof_elt_of_field(type, field) typeof(((type *)0)->field[0])
+/* Check that field f in struct type t2 is an array of t1, of any size */
+#define type_check_varray(t1, t2, f)                                 \
+    (type_check(t1, typeof_elt_of_field(t2, f))                      \
+     + QEMU_BUILD_BUG_ON_ZERO(!QEMU_IS_ARRAY(((t2 *)0)->f)))
 
 #define vmstate_offset_value(_state, _field, _type)                  \
     (offsetof(_state, _field) +                                      \
@@ -253,6 +264,10 @@  extern const VMStateInfo vmstate_info_qtailq;
     vmstate_offset_array(_state, _field, uint8_t,                    \
                          sizeof(typeof_field(_state, _field)))
 
+#define vmstate_offset_varray(_state, _field, _type)                 \
+    (offsetof(_state, _field) +                                      \
+     type_check_varray(_type, _state, _field))
+
 /* In the macros below, if there is a _version, that means the macro's
  * field will be processed only if the version being received is >=
  * the _version specified.  In general, if you add a new field, you
@@ -347,7 +362,7 @@  extern const VMStateInfo vmstate_info_qtailq;
     .info       = &(_info),                                          \
     .size       = sizeof(_type),                                     \
     .flags      = VMS_VARRAY_UINT32|VMS_MULTIPLY_ELEMENTS,           \
-    .offset     = offsetof(_state, _field),                          \
+    .offset     = vmstate_offset_varray(_state, _field, _type),      \
 }
 
 #define VMSTATE_ARRAY_TEST(_field, _state, _num, _test, _info, _type) {\
@@ -376,7 +391,7 @@  extern const VMStateInfo vmstate_info_qtailq;
     .info       = &(_info),                                          \
     .size       = sizeof(_type),                                     \
     .flags      = VMS_VARRAY_INT32,                                  \
-    .offset     = offsetof(_state, _field),                          \
+    .offset     = vmstate_offset_varray(_state, _field, _type),      \
 }
 
 #define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\
@@ -416,7 +431,7 @@  extern const VMStateInfo vmstate_info_qtailq;
     .info       = &(_info),                                          \
     .size       = sizeof(_type),                                     \
     .flags      = VMS_VARRAY_UINT16,                                 \
-    .offset     = offsetof(_state, _field),                          \
+    .offset     = vmstate_offset_varray(_state, _field, _type),      \
 }
 
 #define VMSTATE_VSTRUCT_TEST(_field, _state, _test, _version, _vmsd, _type, _struct_version) { \
@@ -520,7 +535,7 @@  extern const VMStateInfo vmstate_info_qtailq;
     .vmsd       = &(_vmsd),                                          \
     .size       = sizeof(_type),                                     \
     .flags      = VMS_STRUCT|VMS_VARRAY_UINT8,                       \
-    .offset     = offsetof(_state, _field),                          \
+    .offset     = vmstate_offset_varray(_state, _field, _type),      \
 }
 
 /* a variable length array (i.e. _type *_field) but we know the
@@ -573,7 +588,7 @@  extern const VMStateInfo vmstate_info_qtailq;
     .vmsd       = &(_vmsd),                                          \
     .size       = sizeof(_type),                                     \
     .flags      = VMS_STRUCT|VMS_VARRAY_INT32,                       \
-    .offset     = offsetof(_state, _field),                          \
+    .offset     = vmstate_offset_varray(_state, _field, _type),      \
 }
 
 #define VMSTATE_STRUCT_VARRAY_UINT32(_field, _state, _field_num, _version, _vmsd, _type) { \
@@ -583,7 +598,7 @@  extern const VMStateInfo vmstate_info_qtailq;
     .vmsd       = &(_vmsd),                                          \
     .size       = sizeof(_type),                                     \
     .flags      = VMS_STRUCT|VMS_VARRAY_UINT32,                      \
-    .offset     = offsetof(_state, _field),                          \
+    .offset     = vmstate_offset_varray(_state, _field, _type),      \
 }
 
 #define VMSTATE_STRUCT_VARRAY_ALLOC(_field, _state, _field_num, _version, _vmsd, _type) {\