xref: /qemu/rust/qemu-api/tests/vmstate_tests.rs (revision 8ed7c0b6488a7f20318d6ba414f1cbcd0ed92afe)
1 // Copyright (C) 2025 Intel Corporation.
2 // Author(s): Zhao Liu <zhai1.liu@intel.com>
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 
5 use std::{ffi::CStr, mem::size_of, os::raw::c_void, ptr::NonNull, slice};
6 
7 use qemu_api::{
8     bindings::{
9         vmstate_info_bool, vmstate_info_int32, vmstate_info_int64, vmstate_info_int8,
10         vmstate_info_uint64, vmstate_info_uint8, vmstate_info_unused_buffer, VMStateFlags,
11     },
12     c_str,
13     cell::{BqlCell, Opaque},
14     impl_vmstate_forward,
15     vmstate::{VMStateDescription, VMStateField},
16     vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused, vmstate_validate,
17     zeroable::Zeroable,
18 };
19 
20 const FOO_ARRAY_MAX: usize = 3;
21 
22 // =========================== Test VMSTATE_FOOA ===========================
23 // Test the use cases of the vmstate macro, corresponding to the following C
24 // macro variants:
25 //   * VMSTATE_FOOA:
26 //     - VMSTATE_U16
27 //     - VMSTATE_UNUSED
28 //     - VMSTATE_VARRAY_UINT16_UNSAFE
29 //     - VMSTATE_VARRAY_MULTIPLY
30 #[repr(C)]
31 #[derive(Default, qemu_api_macros::offsets)]
32 struct FooA {
33     arr: [u8; FOO_ARRAY_MAX],
34     num: u16,
35     arr_mul: [i8; FOO_ARRAY_MAX],
36     num_mul: u32,
37     elem: i8,
38 }
39 
40 static VMSTATE_FOOA: VMStateDescription = VMStateDescription {
41     name: c_str!("foo_a").as_ptr(),
42     version_id: 1,
43     minimum_version_id: 1,
44     fields: vmstate_fields! {
45         vmstate_of!(FooA, elem),
46         vmstate_unused!(size_of::<i64>()),
47         vmstate_of!(FooA, arr[0 .. num]).with_version_id(0),
48         vmstate_of!(FooA, arr_mul[0 .. num_mul * 16]),
49     },
50     ..Zeroable::ZERO
51 };
52 
53 #[test]
54 fn test_vmstate_uint16() {
55     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
56 
57     // 1st VMStateField ("elem") in VMSTATE_FOOA (corresponding to VMSTATE_UINT16)
58     assert_eq!(
59         unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
60         b"elem\0"
61     );
62     assert_eq!(foo_fields[0].offset, 16);
63     assert_eq!(foo_fields[0].num_offset, 0);
64     assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int8 });
65     assert_eq!(foo_fields[0].version_id, 0);
66     assert_eq!(foo_fields[0].size, 1);
67     assert_eq!(foo_fields[0].num, 0);
68     assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
69     assert!(foo_fields[0].vmsd.is_null());
70     assert!(foo_fields[0].field_exists.is_none());
71 }
72 
73 #[test]
74 fn test_vmstate_unused() {
75     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
76 
77     // 2nd VMStateField ("unused") in VMSTATE_FOOA (corresponding to VMSTATE_UNUSED)
78     assert_eq!(
79         unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
80         b"unused\0"
81     );
82     assert_eq!(foo_fields[1].offset, 0);
83     assert_eq!(foo_fields[1].num_offset, 0);
84     assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_unused_buffer });
85     assert_eq!(foo_fields[1].version_id, 0);
86     assert_eq!(foo_fields[1].size, 8);
87     assert_eq!(foo_fields[1].num, 0);
88     assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_BUFFER);
89     assert!(foo_fields[1].vmsd.is_null());
90     assert!(foo_fields[1].field_exists.is_none());
91 }
92 
93 #[test]
94 fn test_vmstate_varray_uint16_unsafe() {
95     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
96 
97     // 3rd VMStateField ("arr") in VMSTATE_FOOA (corresponding to
98     // VMSTATE_VARRAY_UINT16_UNSAFE)
99     assert_eq!(
100         unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
101         b"arr\0"
102     );
103     assert_eq!(foo_fields[2].offset, 0);
104     assert_eq!(foo_fields[2].num_offset, 4);
105     assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
106     assert_eq!(foo_fields[2].version_id, 0);
107     assert_eq!(foo_fields[2].size, 1);
108     assert_eq!(foo_fields[2].num, 0);
109     assert_eq!(foo_fields[2].flags, VMStateFlags::VMS_VARRAY_UINT16);
110     assert!(foo_fields[2].vmsd.is_null());
111     assert!(foo_fields[2].field_exists.is_none());
112 }
113 
114 #[test]
115 fn test_vmstate_varray_multiply() {
116     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOA.fields, 5) };
117 
118     // 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to
119     // VMSTATE_VARRAY_MULTIPLY)
120     assert_eq!(
121         unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
122         b"arr_mul\0"
123     );
124     assert_eq!(foo_fields[3].offset, 6);
125     assert_eq!(foo_fields[3].num_offset, 12);
126     assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_int8 });
127     assert_eq!(foo_fields[3].version_id, 0);
128     assert_eq!(foo_fields[3].size, 1);
129     assert_eq!(foo_fields[3].num, 16);
130     assert_eq!(
131         foo_fields[3].flags.0,
132         VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
133     );
134     assert!(foo_fields[3].vmsd.is_null());
135     assert!(foo_fields[3].field_exists.is_none());
136 
137     // The last VMStateField in VMSTATE_FOOA.
138     assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
139 }
140 
141 // =========================== Test VMSTATE_FOOB ===========================
142 // Test the use cases of the vmstate macro, corresponding to the following C
143 // macro variants:
144 //   * VMSTATE_FOOB:
145 //     - VMSTATE_BOOL_V
146 //     - VMSTATE_U64
147 //     - VMSTATE_STRUCT_VARRAY_UINT8
148 //     - (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32
149 //     - VMSTATE_ARRAY
150 //     - VMSTATE_STRUCT_VARRAY_UINT8 with BqlCell wrapper & test_fn
151 #[repr(C)]
152 #[derive(Default, qemu_api_macros::offsets)]
153 struct FooB {
154     arr_a: [FooA; FOO_ARRAY_MAX],
155     num_a: u8,
156     arr_a_mul: [FooA; FOO_ARRAY_MAX],
157     num_a_mul: u32,
158     wrap: BqlCell<u64>,
159     val: bool,
160     // FIXME: Use Timer array. Now we can't since it's hard to link savevm.c to test.
161     arr_i64: [i64; FOO_ARRAY_MAX],
162     arr_a_wrap: [FooA; FOO_ARRAY_MAX],
163     num_a_wrap: BqlCell<u32>,
164 }
165 
166 fn validate_foob(_state: &FooB, _version_id: u8) -> bool {
167     true
168 }
169 
170 static VMSTATE_FOOB: VMStateDescription = VMStateDescription {
171     name: c_str!("foo_b").as_ptr(),
172     version_id: 2,
173     minimum_version_id: 1,
174     fields: vmstate_fields! {
175         vmstate_of!(FooB, val).with_version_id(2),
176         vmstate_of!(FooB, wrap),
177         vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).with_version_id(1),
178         vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE_FOOA, FooA).with_version_id(2),
179         vmstate_of!(FooB, arr_i64),
180         vmstate_struct!(FooB, arr_a_wrap[0 .. num_a_wrap], &VMSTATE_FOOA, FooA, validate_foob),
181     },
182     ..Zeroable::ZERO
183 };
184 
185 #[test]
186 fn test_vmstate_bool_v() {
187     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) };
188 
189     // 1st VMStateField ("val") in VMSTATE_FOOB (corresponding to VMSTATE_BOOL_V)
190     assert_eq!(
191         unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
192         b"val\0"
193     );
194     assert_eq!(foo_fields[0].offset, 136);
195     assert_eq!(foo_fields[0].num_offset, 0);
196     assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_bool });
197     assert_eq!(foo_fields[0].version_id, 2);
198     assert_eq!(foo_fields[0].size, 1);
199     assert_eq!(foo_fields[0].num, 0);
200     assert_eq!(foo_fields[0].flags, VMStateFlags::VMS_SINGLE);
201     assert!(foo_fields[0].vmsd.is_null());
202     assert!(foo_fields[0].field_exists.is_none());
203 }
204 
205 #[test]
206 fn test_vmstate_uint64() {
207     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) };
208 
209     // 2nd VMStateField ("wrap") in VMSTATE_FOOB (corresponding to VMSTATE_U64)
210     assert_eq!(
211         unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
212         b"wrap\0"
213     );
214     assert_eq!(foo_fields[1].offset, 128);
215     assert_eq!(foo_fields[1].num_offset, 0);
216     assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_uint64 });
217     assert_eq!(foo_fields[1].version_id, 0);
218     assert_eq!(foo_fields[1].size, 8);
219     assert_eq!(foo_fields[1].num, 0);
220     assert_eq!(foo_fields[1].flags, VMStateFlags::VMS_SINGLE);
221     assert!(foo_fields[1].vmsd.is_null());
222     assert!(foo_fields[1].field_exists.is_none());
223 }
224 
225 #[test]
226 fn test_vmstate_struct_varray_uint8() {
227     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) };
228 
229     // 3rd VMStateField ("arr_a") in VMSTATE_FOOB (corresponding to
230     // VMSTATE_STRUCT_VARRAY_UINT8)
231     assert_eq!(
232         unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
233         b"arr_a\0"
234     );
235     assert_eq!(foo_fields[2].offset, 0);
236     assert_eq!(foo_fields[2].num_offset, 60);
237     assert!(foo_fields[2].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
238     assert_eq!(foo_fields[2].version_id, 1);
239     assert_eq!(foo_fields[2].size, 20);
240     assert_eq!(foo_fields[2].num, 0);
241     assert_eq!(
242         foo_fields[2].flags.0,
243         VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_VARRAY_UINT8.0
244     );
245     assert_eq!(foo_fields[2].vmsd, &VMSTATE_FOOA);
246     assert!(foo_fields[2].field_exists.is_none());
247 }
248 
249 #[test]
250 fn test_vmstate_struct_varray_uint32_multiply() {
251     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) };
252 
253     // 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to
254     // (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32)
255     assert_eq!(
256         unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
257         b"arr_a_mul\0"
258     );
259     assert_eq!(foo_fields[3].offset, 64);
260     assert_eq!(foo_fields[3].num_offset, 124);
261     assert!(foo_fields[3].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
262     assert_eq!(foo_fields[3].version_id, 2);
263     assert_eq!(foo_fields[3].size, 20);
264     assert_eq!(foo_fields[3].num, 32);
265     assert_eq!(
266         foo_fields[3].flags.0,
267         VMStateFlags::VMS_STRUCT.0
268             | VMStateFlags::VMS_VARRAY_UINT32.0
269             | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0
270     );
271     assert_eq!(foo_fields[3].vmsd, &VMSTATE_FOOA);
272     assert!(foo_fields[3].field_exists.is_none());
273 }
274 
275 #[test]
276 fn test_vmstate_macro_array() {
277     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) };
278 
279     // 5th VMStateField ("arr_i64") in VMSTATE_FOOB (corresponding to
280     // VMSTATE_ARRAY)
281     assert_eq!(
282         unsafe { CStr::from_ptr(foo_fields[4].name) }.to_bytes_with_nul(),
283         b"arr_i64\0"
284     );
285     assert_eq!(foo_fields[4].offset, 144);
286     assert_eq!(foo_fields[4].num_offset, 0);
287     assert_eq!(foo_fields[4].info, unsafe { &vmstate_info_int64 });
288     assert_eq!(foo_fields[4].version_id, 0);
289     assert_eq!(foo_fields[4].size, 8);
290     assert_eq!(foo_fields[4].num, FOO_ARRAY_MAX as i32);
291     assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_ARRAY);
292     assert!(foo_fields[4].vmsd.is_null());
293     assert!(foo_fields[4].field_exists.is_none());
294 }
295 
296 #[test]
297 fn test_vmstate_struct_varray_uint8_wrapper() {
298     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) };
299     let mut foo_b: FooB = Default::default();
300     let foo_b_p = std::ptr::addr_of_mut!(foo_b).cast::<c_void>();
301 
302     // 6th VMStateField ("arr_a_wrap") in VMSTATE_FOOB (corresponding to
303     // VMSTATE_STRUCT_VARRAY_UINT8). Other fields are checked in
304     // test_vmstate_struct_varray_uint8.
305     assert_eq!(
306         unsafe { CStr::from_ptr(foo_fields[5].name) }.to_bytes_with_nul(),
307         b"arr_a_wrap\0"
308     );
309     assert_eq!(foo_fields[5].num_offset, 228);
310     assert!(unsafe { foo_fields[5].field_exists.unwrap()(foo_b_p, 0) });
311 
312     // The last VMStateField in VMSTATE_FOOB.
313     assert_eq!(foo_fields[6].flags, VMStateFlags::VMS_END);
314 }
315 
316 // =========================== Test VMSTATE_FOOC ===========================
317 // Test the use cases of the vmstate macro, corresponding to the following C
318 // macro variants:
319 //   * VMSTATE_FOOC:
320 //     - VMSTATE_POINTER
321 //     - VMSTATE_ARRAY_OF_POINTER
322 struct FooCWrapper([Opaque<*mut u8>; FOO_ARRAY_MAX]); // Though Opaque<> array is almost impossible.
323 
324 impl_vmstate_forward!(FooCWrapper);
325 
326 #[repr(C)]
327 #[derive(qemu_api_macros::offsets)]
328 struct FooC {
329     ptr: *const i32,
330     ptr_a: NonNull<FooA>,
331     arr_ptr: [Box<u8>; FOO_ARRAY_MAX],
332     arr_ptr_wrap: FooCWrapper,
333 }
334 
335 static VMSTATE_FOOC: VMStateDescription = VMStateDescription {
336     name: c_str!("foo_c").as_ptr(),
337     version_id: 3,
338     minimum_version_id: 1,
339     fields: vmstate_fields! {
340         vmstate_of!(FooC, ptr).with_version_id(2),
341         // FIXME: Currently vmstate_struct doesn't support the pointer to structure.
342         // VMSTATE_STRUCT_POINTER: vmstate_struct!(FooC, ptr_a, VMSTATE_FOOA, NonNull<FooA>)
343         vmstate_unused!(size_of::<NonNull<FooA>>()),
344         vmstate_of!(FooC, arr_ptr),
345         vmstate_of!(FooC, arr_ptr_wrap),
346     },
347     ..Zeroable::ZERO
348 };
349 
350 const PTR_SIZE: usize = size_of::<*mut ()>();
351 
352 #[test]
353 fn test_vmstate_pointer() {
354     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
355 
356     // 1st VMStateField ("ptr") in VMSTATE_FOOC (corresponding to VMSTATE_POINTER)
357     assert_eq!(
358         unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
359         b"ptr\0"
360     );
361     assert_eq!(foo_fields[0].offset, 0);
362     assert_eq!(foo_fields[0].num_offset, 0);
363     assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int32 });
364     assert_eq!(foo_fields[0].version_id, 2);
365     assert_eq!(foo_fields[0].size, 4);
366     assert_eq!(foo_fields[0].num, 0);
367     assert_eq!(
368         foo_fields[0].flags.0,
369         VMStateFlags::VMS_SINGLE.0 | VMStateFlags::VMS_POINTER.0
370     );
371     assert!(foo_fields[0].vmsd.is_null());
372     assert!(foo_fields[0].field_exists.is_none());
373 }
374 
375 #[test]
376 fn test_vmstate_macro_array_of_pointer() {
377     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
378 
379     // 3rd VMStateField ("arr_ptr") in VMSTATE_FOOC (corresponding to
380     // VMSTATE_ARRAY_OF_POINTER)
381     assert_eq!(
382         unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
383         b"arr_ptr\0"
384     );
385     assert_eq!(foo_fields[2].offset, 2 * PTR_SIZE);
386     assert_eq!(foo_fields[2].num_offset, 0);
387     assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
388     assert_eq!(foo_fields[2].version_id, 0);
389     assert_eq!(foo_fields[2].size, PTR_SIZE);
390     assert_eq!(foo_fields[2].num, FOO_ARRAY_MAX as i32);
391     assert_eq!(
392         foo_fields[2].flags.0,
393         VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0
394     );
395     assert!(foo_fields[2].vmsd.is_null());
396     assert!(foo_fields[2].field_exists.is_none());
397 }
398 
399 #[test]
400 fn test_vmstate_macro_array_of_pointer_wrapped() {
401     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOC.fields, 6) };
402 
403     // 4th VMStateField ("arr_ptr_wrap") in VMSTATE_FOOC (corresponding to
404     // VMSTATE_ARRAY_OF_POINTER)
405     assert_eq!(
406         unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(),
407         b"arr_ptr_wrap\0"
408     );
409     assert_eq!(foo_fields[3].offset, (FOO_ARRAY_MAX + 2) * PTR_SIZE);
410     assert_eq!(foo_fields[3].num_offset, 0);
411     assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_uint8 });
412     assert_eq!(foo_fields[3].version_id, 0);
413     assert_eq!(foo_fields[3].size, PTR_SIZE);
414     assert_eq!(foo_fields[3].num, FOO_ARRAY_MAX as i32);
415     assert_eq!(
416         foo_fields[3].flags.0,
417         VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0
418     );
419     assert!(foo_fields[3].vmsd.is_null());
420     assert!(foo_fields[3].field_exists.is_none());
421 
422     // The last VMStateField in VMSTATE_FOOC.
423     assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END);
424 }
425 
426 // =========================== Test VMSTATE_FOOD ===========================
427 // Test the use cases of the vmstate macro, corresponding to the following C
428 // macro variants:
429 //   * VMSTATE_FOOD:
430 //     - VMSTATE_VALIDATE
431 
432 // Add more member fields when vmstate_of/vmstate_struct support "test"
433 // parameter.
434 struct FooD;
435 
436 impl FooD {
437     fn validate_food_0(&self, _version_id: u8) -> bool {
438         true
439     }
440 
441     fn validate_food_1(_state: &FooD, _version_id: u8) -> bool {
442         false
443     }
444 }
445 
446 fn validate_food_2(_state: &FooD, _version_id: u8) -> bool {
447     true
448 }
449 
450 static VMSTATE_FOOD: VMStateDescription = VMStateDescription {
451     name: c_str!("foo_d").as_ptr(),
452     version_id: 3,
453     minimum_version_id: 1,
454     fields: vmstate_fields! {
455         vmstate_validate!(FooD, c_str!("foo_d_0"), FooD::validate_food_0),
456         vmstate_validate!(FooD, c_str!("foo_d_1"), FooD::validate_food_1),
457         vmstate_validate!(FooD, c_str!("foo_d_2"), validate_food_2),
458     },
459     ..Zeroable::ZERO
460 };
461 
462 #[test]
463 fn test_vmstate_validate() {
464     let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOD.fields, 4) };
465     let mut foo_d = FooD;
466     let foo_d_p = std::ptr::addr_of_mut!(foo_d).cast::<c_void>();
467 
468     // 1st VMStateField in VMSTATE_FOOD
469     assert_eq!(
470         unsafe { CStr::from_ptr(foo_fields[0].name) }.to_bytes_with_nul(),
471         b"foo_d_0\0"
472     );
473     assert_eq!(foo_fields[0].offset, 0);
474     assert_eq!(foo_fields[0].num_offset, 0);
475     assert!(foo_fields[0].info.is_null());
476     assert_eq!(foo_fields[0].version_id, 0);
477     assert_eq!(foo_fields[0].size, 0);
478     assert_eq!(foo_fields[0].num, 0);
479     assert_eq!(
480         foo_fields[0].flags.0,
481         VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_MUST_EXIST.0
482     );
483     assert!(foo_fields[0].vmsd.is_null());
484     assert!(unsafe { foo_fields[0].field_exists.unwrap()(foo_d_p, 0) });
485 
486     // 2nd VMStateField in VMSTATE_FOOD
487     assert_eq!(
488         unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(),
489         b"foo_d_1\0"
490     );
491     assert!(!unsafe { foo_fields[1].field_exists.unwrap()(foo_d_p, 1) });
492 
493     // 3rd VMStateField in VMSTATE_FOOD
494     assert_eq!(
495         unsafe { CStr::from_ptr(foo_fields[2].name) }.to_bytes_with_nul(),
496         b"foo_d_2\0"
497     );
498     assert!(unsafe { foo_fields[2].field_exists.unwrap()(foo_d_p, 2) });
499 
500     // The last VMStateField in VMSTATE_FOOD.
501     assert_eq!(foo_fields[3].flags, VMStateFlags::VMS_END);
502 }
503