Re: [Qemu-devel] [PATCH 1/7] Introduce strtosz() library function to convert a string to a byte count.

2010-10-11 Thread Markus Armbruster
jes.soren...@redhat.com writes:

 From: Jes Sorensen jes.soren...@redhat.com

 strtosz() returns -1 on error.

 v2 renamed from strtobytes() to strtosz() as suggested by Markus.

 Signed-off-by: Jes Sorensen jes.soren...@redhat.com
 ---
  cutils.c  |   39 +++
  qemu-common.h |1 +
  vl.c  |   31 ++-
  3 files changed, 50 insertions(+), 21 deletions(-)

 diff --git a/cutils.c b/cutils.c
 index 5883737..ee591c5 100644
 --- a/cutils.c
 +++ b/cutils.c
 @@ -283,3 +283,42 @@ int fcntl_setfl(int fd, int flag)
  }
  #endif
  
 +/*
 + * Convert string to bytes, allowing either K/k for KB, M/m for MB,
 + * G/g for GB or T/t for TB. Default without any postfix is MB.
 + * End pointer will be returned in *end, if end is valid.
 + * Return -1 on error.
 + */
 +ssize_t strtosz(const char *nptr, char **end)
 +{
 +int64_t value;

long long, please, because that's what strtoll() returns.

 +char *endptr;
 +
 +value = strtoll(nptr, endptr, 0);
 +switch (*endptr++) {
 +case 'K':
 +case 'k':
 +value = 10;
 +break;
 +case 0:
 +case 'M':
 +case 'm':
 +value = 20;
 +break;
 +case 'G':
 +case 'g':
 +value = 30;
 +break;
 +case 'T':
 +case 't':
 +value = 40;
 +break;
 +default:
 +value = -1;
 +}
 +
 +if (end)
 +*end = endptr;
 +
 +return value;

Casts value to ssize_t, which might truncate.

 +}

Sloppy use of strtoll().

Both tolerable as long as the patch doesn't make things worse.  Let's
see:

 diff --git a/qemu-common.h b/qemu-common.h
 index 81aafa0..0a062d4 100644
 --- a/qemu-common.h
 +++ b/qemu-common.h
 @@ -153,6 +153,7 @@ time_t mktimegm(struct tm *tm);
  int qemu_fls(int i);
  int qemu_fdatasync(int fd);
  int fcntl_setfl(int fd, int flag);
 +ssize_t strtosz(const char *nptr, char **end);
  
  /* path.c */
  void init_paths(const char *prefix);
 diff --git a/vl.c b/vl.c
 index df414ef..6043fa2 100644
 --- a/vl.c
 +++ b/vl.c
 @@ -734,16 +734,13 @@ static void numa_add(const char *optarg)
  if (get_param_value(option, 128, mem, optarg) == 0) {
  node_mem[nodenr] = 0;
  } else {
 -value = strtoull(option, endptr, 0);
 -switch (*endptr) {
 -case 0: case 'M': case 'm':
 -value = 20;
 -break;
 -case 'G': case 'g':
 -value = 30;
 -break;
 +ssize_t sval;
 +sval = strtosz(option, NULL);
 +if (sval  0) {
 +fprintf(stderr, qemu: invalid numa mem size: %s\n, optarg);
 +exit(1);

Before  After
Invalid number  silently interpreted as zerono change
Overflowsilently capped to ULLONG_MAX   LLONG_MAX, then
trunc ssize_t
Invalid size suffix silently ignoredrejected

  }
 -node_mem[nodenr] = value;
 +node_mem[nodenr] = sval;
  }
  if (get_param_value(option, 128, cpus, optarg) == 0) {
  node_cpumask[nodenr] = 0;
 @@ -2163,18 +2160,10 @@ int main(int argc, char **argv, char **envp)
  exit(0);
  break;
  case QEMU_OPTION_m: {
 -uint64_t value;
 -char *ptr;
 +ssize_t value;
  
 -value = strtoul(optarg, ptr, 10);
 -switch (*ptr) {
 -case 0: case 'M': case 'm':
 -value = 20;
 -break;
 -case 'G': case 'g':
 -value = 30;
 -break;
 -default:
 +value = strtosz(optarg, NULL);
 +if (value  0) {
  fprintf(stderr, qemu: invalid ram size: %s\n, optarg);
  exit(1);
  }

Before  After
Invalid number  silently interpreted as zerono change
Overflowsilently capped to ULLONG_MAX   LLONG_MAX, then
trunc ssize_t
Invalid size suffix rejectedno change

A bit more context:


   /* On 32-bit hosts, QEMU is limited by virtual address space 
*/
   if (value  (2047  20)  HOST_LONG_BITS == 32) {
   fprintf(stderr, qemu: at most 2047 MB RAM can be 
simulated\n);
   exit(1);
   }
   if (value != (uint64_t)(ram_addr_t)value) {
   fprintf(stderr, qemu: ram size too large\n);
   exit(1);
   }
   ram_size = value;
   break;

I'm afraid you break both 

Re: [Qemu-devel] [PATCH 1/7] Introduce strtosz() library function to convert a string to a byte count.

2010-10-11 Thread Jes Sorensen
On 10/11/10 10:51, Markus Armbruster wrote:
 jes.soren...@redhat.com writes:
 +/*
 + * Convert string to bytes, allowing either K/k for KB, M/m for MB,
 + * G/g for GB or T/t for TB. Default without any postfix is MB.
 + * End pointer will be returned in *end, if end is valid.
 + * Return -1 on error.
 + */
 +ssize_t strtosz(const char *nptr, char **end)
 +{
 +int64_t value;
 
 long long, please, because that's what strtoll() returns.

I merged patches 1-3 as you suggested, so comments based on the combined
patch.

This is longer an issue as it is switched to strtod().

 +char *endptr;
 +
 +value = strtoll(nptr, endptr, 0);
 +switch (*endptr++) {
 +case 'K':
 +case 'k':
 +value = 10;
 +break;
 +case 0:
 +case 'M':
 +case 'm':
 +value = 20;
 +break;
 +case 'G':
 +case 'g':
 +value = 30;
 +break;
 +case 'T':
 +case 't':
 +value = 40;
 +break;
 +default:
 +value = -1;
 +}
 +
 +if (end)
 +*end = endptr;
 +
 +return value;
 
 Casts value to ssize_t, which might truncate.

The new patch does:

int64_t tmpval;
tmpval = (val * mul);
if (tmpval = ~(size_t)0)
goto fail;

so anything that is out of bounds is checked and caught before returning
a possibly truncated valued.

 Sloppy use of strtoll().tmpval = (val * mul);
if (tmpval = ~(size_t)0)
goto fail;
 
 Both tolerable as long as the patch doesn't make things worse.  Let's
 see:
 
 diff --git a/qemu-common.h b/qemu-common.h
 index 81aafa0..0a062d4 100644
 --- a/qemu-common.h
 +++ b/qemu-common.h
 @@ -153,6 +153,7 @@ time_t mktimegm(struct tm *tm);
  int qemu_fls(int i);
  int qemu_fdatasync(int fd);
  int fcntl_setfl(int fd, int flag);
 +ssize_t strtosz(const char *nptr, char **end);
  
  /* path.c */
  void init_paths(const char *prefix);
 diff --git a/vl.c b/vl.c
 index df414ef..6043fa2 100644
 --- a/vl.c
 +++ b/vl.c
 @@ -734,16 +734,13 @@ static void numa_add(const char *optarg)
  if (get_param_value(option, 128, mem, optarg) == 0) {
  node_mem[nodenr] = 0;
  } else {
 -value = strtoull(option, endptr, 0);
 -switch (*endptr) {
 -case 0: case 'M': case 'm':
 -value = 20;
 -break;
 -case 'G': case 'g':
 -value = 30;
 -break;
 +ssize_t sval;
 +sval = strtosz(option, NULL);
 +if (sval  0) {
 +fprintf(stderr, qemu: invalid numa mem size: %s\n, 
 optarg);
 +exit(1);
 
 Before  After
 Invalid number  silently interpreted as zerono change
 Overflowsilently capped to ULLONG_MAX   LLONG_MAX, then
 trunc ssize_t
 Invalid size suffix silently ignoredrejected

What do you mean by invalid number here?

LLONG_MAX seems a reasonable limit, ie. 31 bit on 32 bit hosts or 63
bits on 64 bit hosts. strtosz() is meant to return a size, so IMHO thats
a fair limitation. We could use size_t instead of ssize_t but it would
require ugly casts in any function calling the function to test for error.

 Before  After
 Invalid number  silently interpreted as zerono change
 Overflowsilently capped to ULLONG_MAX   LLONG_MAX, then
 trunc ssize_t
 Invalid size suffix rejectedno change
 
 A bit more context:
 
 
/* On 32-bit hosts, QEMU is limited by virtual address 
 space */
if (value  (2047  20)  HOST_LONG_BITS == 32) {
fprintf(stderr, qemu: at most 2047 MB RAM can be 
 simulated\n);
exit(1);
}
if (value != (uint64_t)(ram_addr_t)value) {
fprintf(stderr, qemu: ram size too large\n);
exit(1);
}
ram_size = value;
break;
 
 I'm afraid you break both conditionals for 32 bit hosts.
 
 On such hosts, ssize_t is 32 bits wide.  strtosz() parses 64 bits
 internally, but truncates to 32 bits silently.

I believe the combined patch is taking care of this fine with the
= ~(size_t)0 comparison. If the value is above that, it returns an
error. For 32 bit hosts that means we should be able to specify 2047MB
RAM fine.

The only place where I see the latter being a potential problem is on
P64 systems such as win64, since ram_addr_t is defined to be unsigned
long, but afaik we don't support win64 anyway. On both 32 bit and LP64
systems sizeof(ram_addr_t) == sizeof(ssize_t), so it should be fine.


 The old code reliably rejects values larger than 2047MiB.  Your
 truncation can change a 

Re: [Qemu-devel] [PATCH 1/7] Introduce strtosz() library function to convert a string to a byte count.

2010-10-11 Thread Markus Armbruster
Jes Sorensen jes.soren...@redhat.com writes:

 On 10/11/10 10:51, Markus Armbruster wrote:
 jes.soren...@redhat.com writes:
 +/*
 + * Convert string to bytes, allowing either K/k for KB, M/m for MB,
 + * G/g for GB or T/t for TB. Default without any postfix is MB.
 + * End pointer will be returned in *end, if end is valid.
 + * Return -1 on error.
 + */
 +ssize_t strtosz(const char *nptr, char **end)
 +{
 +int64_t value;
 
 long long, please, because that's what strtoll() returns.

 I merged patches 1-3 as you suggested, so comments based on the combined
 patch.

 This is longer an issue as it is switched to strtod().

Okay, I'll review it.

 +char *endptr;
 +
 +value = strtoll(nptr, endptr, 0);
 +switch (*endptr++) {
 +case 'K':
 +case 'k':
 +value = 10;
 +break;
 +case 0:
 +case 'M':
 +case 'm':
 +value = 20;
 +break;
 +case 'G':
 +case 'g':
 +value = 30;
 +break;
 +case 'T':
 +case 't':
 +value = 40;
 +break;
 +default:
 +value = -1;
 +}
 +
 +if (end)
 +*end = endptr;
 +
 +return value;
 
 Casts value to ssize_t, which might truncate.

 The new patch does:

 int64_t tmpval;
 tmpval = (val * mul);
 if (tmpval = ~(size_t)0)
 goto fail;

 so anything that is out of bounds is checked and caught before returning
 a possibly truncated valued.

 Sloppy use of strtoll().tmpval = (val * mul);
 if (tmpval = ~(size_t)0)
 goto fail;
 
 Both tolerable as long as the patch doesn't make things worse.  Let's
 see:
 
 diff --git a/qemu-common.h b/qemu-common.h
 index 81aafa0..0a062d4 100644
 --- a/qemu-common.h
 +++ b/qemu-common.h
 @@ -153,6 +153,7 @@ time_t mktimegm(struct tm *tm);
  int qemu_fls(int i);
  int qemu_fdatasync(int fd);
  int fcntl_setfl(int fd, int flag);
 +ssize_t strtosz(const char *nptr, char **end);
  
  /* path.c */
  void init_paths(const char *prefix);
 diff --git a/vl.c b/vl.c
 index df414ef..6043fa2 100644
 --- a/vl.c
 +++ b/vl.c
 @@ -734,16 +734,13 @@ static void numa_add(const char *optarg)
  if (get_param_value(option, 128, mem, optarg) == 0) {
  node_mem[nodenr] = 0;
  } else {
 -value = strtoull(option, endptr, 0);
 -switch (*endptr) {
 -case 0: case 'M': case 'm':
 -value = 20;
 -break;
 -case 'G': case 'g':
 -value = 30;
 -break;
 +ssize_t sval;
 +sval = strtosz(option, NULL);
 +if (sval  0) {
 +fprintf(stderr, qemu: invalid numa mem size: %s\n, 
 optarg);
 +exit(1);
 
 Before  After
 Invalid number  silently interpreted as zerono change
 Overflowsilently capped to ULLONG_MAX   LLONG_MAX, then
 trunc ssize_t
 Invalid size suffix silently ignoredrejected

 What do you mean by invalid number here?

strtoul(nptr, eptr, base)  friends skip whitespace, eat sign + digits,
stop at first unrecognized character.

What if they can't find any digits?  They store nptr in eptr and return
0.

 LLONG_MAX seems a reasonable limit, ie. 31 bit on 32 bit hosts or 63
 bits on 64 bit hosts. strtosz() is meant to return a size, so IMHO thats
 a fair limitation. We could use size_t instead of ssize_t but it would
 require ugly casts in any function calling the function to test for error.

64 bit hosts are fine; 2^63 should remain an acceptable implementation
limit for a while.

The use in main() is fine on 32 bit: the limit is 2047MiB, which fits
into a 32 bit ssize_t.  Wonder why the limit is 2047, not 2048MiB.  Oh
well.

As far as I can see, the use in numa_add() is also fine, because a
node's memory can't exceed total memory.

 Before  After
 Invalid number  silently interpreted as zerono change
 Overflowsilently capped to ULLONG_MAX   LLONG_MAX, then
 trunc ssize_t
 Invalid size suffix rejectedno change
 
 A bit more context:
 
 
/* On 32-bit hosts, QEMU is limited by virtual address 
 space */
if (value  (2047  20)  HOST_LONG_BITS == 32) {
fprintf(stderr, qemu: at most 2047 MB RAM can be 
 simulated\n);
exit(1);
}
if (value != (uint64_t)(ram_addr_t)value) {
fprintf(stderr, qemu: ram size too large\n);
exit(1);
}
ram_size = value;
break;
 
 I'm afraid you break both conditionals for 32 bit hosts.
 
 On such hosts, ssize_t is 32 bits wide.  strtosz() parses 64 bits
 internally, but