@size is declared int64_t. It's set in two places.
The second one assigns the (signed) value of bdrv_getlength(), then
errors out if its negative.
The first one assigns qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0),
i.e. an uint64_t value. What if it exceeds INT64_MAX? Is that even
possible? Turns out it is:
$ qemu-img create -o size=9223372036854775808 foo.img
On closer examination, the code still works as long as converting from
uint64_t to int64_t and back doesn't change the value.
Implementation-defined behavior, but sane implementations behave.
Things actually break elsewhere for such sizes, e.g. file-posix.c's
raw_create().
Clean this up.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
block.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/block.c b/block.c
index ce9cce7..04cce0d 100644
--- a/block.c
+++ b/block.c
@@ -4309,7 +4309,8 @@ void bdrv_img_create(const char *filename, const char *fmt,
QemuOptsList *create_opts = NULL;
QemuOpts *opts = NULL;
const char *backing_fmt, *backing_file;
- int64_t size;
+ uint64_t size;
+ int64_t backing_size;
BlockDriver *drv, *proto_drv;
Error *local_err = NULL;
int ret = 0;
@@ -4414,7 +4415,7 @@ void bdrv_img_create(const char *filename, const char *fmt,
bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
&local_err);
g_free(full_backing);
- if (!bs && size != -1) {
+ if (!bs && size != UINT64_MAX) {
/* Couldn't open BS, but we have a size, so it's nonfatal */
warn_reportf_err(local_err,
"Could not verify backing image. "
@@ -4426,22 +4427,24 @@ void bdrv_img_create(const char *filename, const char *fmt,
"Could not open backing image to determine size.\n");
goto out;
} else {
- if (size == -1) {
+ if (size == UINT64_MAX) {
/* Opened BS, have no size */
- size = bdrv_getlength(bs);
- if (size < 0) {
- error_setg_errno(errp, -size, "Could not get size of '%s'",
+ backing_size = bdrv_getlength(bs);
+ if (backing_size < 0) {
+ error_setg_errno(errp, -backing_size,
+ "Could not get size of '%s'",
backing_file);
bdrv_unref(bs);
goto out;
}
+ size = backing_size;
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort);
}
bdrv_unref(bs);
}
} /* (backing_file && !(flags & BDRV_O_NO_BACKING)) */
- if (size == -1) {
+ if (size == UINT64_MAX) {
error_setg(errp, "Image creation needs a size parameter");
goto out;
}
--
2.7.5