migration/vmstate: fix array of ptr with nullptrs
Make VMS_ARRAY_OF_POINTER cope with null pointers. Previously the reward for trying to migrate an array with some null pointers in it was an illegal memory access, that is a swift and painless death of the process. Let's make vmstate cope with this scenario. The general approach is, when we encounter a null pointer (element), instead of following the pointer to save/load the data behind it, we save/load a placeholder. This way we can detect if we expected a null pointer at the load side but not null data was saved instead. Signed-off-by: Halil Pasic <pasic@linux.vnet.ibm.com> Reviewed-by: Guenther Hutzl <hutzl@linux.vnet.ibm.com> Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com> Message-Id: <20170222160119.52771-4-pasic@linux.vnet.ibm.com> Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
This commit is contained in:
parent
cbfda0e6cf
commit
07d4e69147
@ -253,6 +253,10 @@ extern const VMStateInfo vmstate_info_uint16;
|
|||||||
extern const VMStateInfo vmstate_info_uint32;
|
extern const VMStateInfo vmstate_info_uint32;
|
||||||
extern const VMStateInfo vmstate_info_uint64;
|
extern const VMStateInfo vmstate_info_uint64;
|
||||||
|
|
||||||
|
/** Put this in the stream when migrating a null pointer.*/
|
||||||
|
#define VMS_NULLPTR_MARKER (0x30U) /* '0' */
|
||||||
|
extern const VMStateInfo vmstate_info_nullptr;
|
||||||
|
|
||||||
extern const VMStateInfo vmstate_info_float64;
|
extern const VMStateInfo vmstate_info_float64;
|
||||||
extern const VMStateInfo vmstate_info_cpudouble;
|
extern const VMStateInfo vmstate_info_cpudouble;
|
||||||
|
|
||||||
|
@ -117,7 +117,11 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
|
|||||||
if (field->flags & VMS_ARRAY_OF_POINTER) {
|
if (field->flags & VMS_ARRAY_OF_POINTER) {
|
||||||
curr_elem = *(void **)curr_elem;
|
curr_elem = *(void **)curr_elem;
|
||||||
}
|
}
|
||||||
if (field->flags & VMS_STRUCT) {
|
if (!curr_elem) {
|
||||||
|
/* if null pointer check placeholder and do not follow */
|
||||||
|
assert(field->flags & VMS_ARRAY_OF_POINTER);
|
||||||
|
ret = vmstate_info_nullptr.get(f, curr_elem, size, NULL);
|
||||||
|
} else if (field->flags & VMS_STRUCT) {
|
||||||
ret = vmstate_load_state(f, field->vmsd, curr_elem,
|
ret = vmstate_load_state(f, field->vmsd, curr_elem,
|
||||||
field->vmsd->version_id);
|
field->vmsd->version_id);
|
||||||
} else {
|
} else {
|
||||||
@ -332,7 +336,11 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
|
|||||||
assert(curr_elem);
|
assert(curr_elem);
|
||||||
curr_elem = *(void **)curr_elem;
|
curr_elem = *(void **)curr_elem;
|
||||||
}
|
}
|
||||||
if (field->flags & VMS_STRUCT) {
|
if (!curr_elem) {
|
||||||
|
/* if null pointer write placeholder and do not follow */
|
||||||
|
assert(field->flags & VMS_ARRAY_OF_POINTER);
|
||||||
|
vmstate_info_nullptr.put(f, curr_elem, size, NULL, NULL);
|
||||||
|
} else if (field->flags & VMS_STRUCT) {
|
||||||
vmstate_save_state(f, field->vmsd, curr_elem, vmdesc_loop);
|
vmstate_save_state(f, field->vmsd, curr_elem, vmdesc_loop);
|
||||||
} else {
|
} else {
|
||||||
field->info->put(f, curr_elem, size, field, vmdesc_loop);
|
field->info->put(f, curr_elem, size, field, vmdesc_loop);
|
||||||
@ -747,6 +755,34 @@ const VMStateInfo vmstate_info_uint64 = {
|
|||||||
.put = put_uint64,
|
.put = put_uint64,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int get_nullptr(QEMUFile *f, void *pv, size_t size, VMStateField *field)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (qemu_get_byte(f) == VMS_NULLPTR_MARKER) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int put_nullptr(QEMUFile *f, void *pv, size_t size,
|
||||||
|
VMStateField *field, QJSON *vmdesc)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (pv == NULL) {
|
||||||
|
qemu_put_byte(f, VMS_NULLPTR_MARKER);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
error_report("vmstate: put_nullptr must be called with pv == NULL");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VMStateInfo vmstate_info_nullptr = {
|
||||||
|
.name = "uint64",
|
||||||
|
.get = get_nullptr,
|
||||||
|
.put = put_nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
/* 64 bit unsigned int. See that the received value is the same than the one
|
/* 64 bit unsigned int. See that the received value is the same than the one
|
||||||
in the field */
|
in the field */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user