]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
util: new stricter unsigned int parsing
authorEric Blake <eblake@redhat.com>
Thu, 1 May 2014 02:11:09 +0000 (20:11 -0600)
committerEric Blake <eblake@redhat.com>
Thu, 1 May 2014 21:11:02 +0000 (15:11 -0600)
strtoul() is required to parse negative numbers as their
twos-complement positive counterpart.  But sometimes we want
to reject negative numbers.  Add new functions to do this.
The 'p' suffix is a mnemonic for 'positive' (technically it
also parses 0, but 'non-negative' doesn't lend itself to a
nice one-letter suffix).

* src/util/virstring.h (virStrToLong_uip, virStrToLong_ulp)
(virStrToLong_ullp): New prototypes.
* src/util/virstring.c (virStrToLong_uip, virStrToLong_ulp)
(virStrToLong_ullp): New functions.
* src/libvirt_private.syms (virstring.h): Export them.
* tests/virstringtest.c (testStringToLong): Test them.

Signed-off-by: Eric Blake <eblake@redhat.com>
src/libvirt_private.syms
src/util/virstring.c
src/util/virstring.h
tests/virstringtest.c

index 4cfaefc044d631b1993127e177e944a47e1b89e5..cc3ae2c290398b40ebb4c59aa2dbc88e94062e26 100644 (file)
@@ -1899,8 +1899,11 @@ virStrToLong_i;
 virStrToLong_l;
 virStrToLong_ll;
 virStrToLong_ui;
+virStrToLong_uip;
 virStrToLong_ul;
 virStrToLong_ull;
+virStrToLong_ullp;
+virStrToLong_ulp;
 virTrimSpaces;
 virVasprintfInternal;
 
index b5fc6380f607264b7b9db7afe37db3471d28599f..7a8430e847da165595cf857817881ed7375d9a3a 100644 (file)
@@ -211,7 +211,9 @@ virStrToLong_i(char const *s, char **end_ptr, int base, int *result)
     return 0;
 }
 
-/* Just like virStrToLong_i, above, but produce an "unsigned int" value.  */
+/* Just like virStrToLong_i, above, but produce an "unsigned int"
+ * value.  This version allows twos-complement wraparound of negative
+ * numbers. */
 int
 virStrToLong_ui(char const *s, char **end_ptr, int base, unsigned int *result)
 {
@@ -242,6 +244,27 @@ virStrToLong_ui(char const *s, char **end_ptr, int base, unsigned int *result)
     return 0;
 }
 
+/* Just like virStrToLong_i, above, but produce an "unsigned int"
+ * value.  This version rejects any negative signs.  */
+int
+virStrToLong_uip(char const *s, char **end_ptr, int base, unsigned int *result)
+{
+    unsigned long int val;
+    char *p;
+    bool err = false;
+
+    errno = 0;
+    val = strtoul(s, &p, base); /* exempt from syntax-check */
+    err = (memchr(s, '-', p - s) ||
+           errno || (!end_ptr && *p) || p == s || (unsigned int) val != val);
+    if (end_ptr)
+        *end_ptr = p;
+    if (err)
+        return -1;
+    *result = val;
+    return 0;
+}
+
 /* Just like virStrToLong_i, above, but produce a "long" value.  */
 int
 virStrToLong_l(char const *s, char **end_ptr, int base, long *result)
@@ -261,7 +284,9 @@ virStrToLong_l(char const *s, char **end_ptr, int base, long *result)
     return 0;
 }
 
-/* Just like virStrToLong_i, above, but produce an "unsigned long" value.  */
+/* Just like virStrToLong_i, above, but produce an "unsigned long"
+ * value.  This version allows twos-complement wraparound of negative
+ * numbers. */
 int
 virStrToLong_ul(char const *s, char **end_ptr, int base, unsigned long *result)
 {
@@ -280,6 +305,28 @@ virStrToLong_ul(char const *s, char **end_ptr, int base, unsigned long *result)
     return 0;
 }
 
+/* Just like virStrToLong_i, above, but produce an "unsigned long"
+ * value.  This version rejects any negative signs.  */
+int
+virStrToLong_ulp(char const *s, char **end_ptr, int base,
+                 unsigned long *result)
+{
+    unsigned long int val;
+    char *p;
+    int err;
+
+    errno = 0;
+    val = strtoul(s, &p, base); /* exempt from syntax-check */
+    err = (memchr(s, '-', p - s) ||
+           errno || (!end_ptr && *p) || p == s);
+    if (end_ptr)
+        *end_ptr = p;
+    if (err)
+        return -1;
+    *result = val;
+    return 0;
+}
+
 /* Just like virStrToLong_i, above, but produce a "long long" value.  */
 int
 virStrToLong_ll(char const *s, char **end_ptr, int base, long long *result)
@@ -299,9 +346,12 @@ virStrToLong_ll(char const *s, char **end_ptr, int base, long long *result)
     return 0;
 }
 
-/* Just like virStrToLong_i, above, but produce an "unsigned long long" value.  */
+/* Just like virStrToLong_i, above, but produce an "unsigned long
+ * long" value.  This version allows twos-complement wraparound of
+ * negative numbers. */
 int
-virStrToLong_ull(char const *s, char **end_ptr, int base, unsigned long long *result)
+virStrToLong_ull(char const *s, char **end_ptr, int base,
+                 unsigned long long *result)
 {
     unsigned long long val;
     char *p;
@@ -318,6 +368,28 @@ virStrToLong_ull(char const *s, char **end_ptr, int base, unsigned long long *re
     return 0;
 }
 
+/* Just like virStrToLong_i, above, but produce an "unsigned long
+ * long" value.  This version rejects any negative signs.  */
+int
+virStrToLong_ullp(char const *s, char **end_ptr, int base,
+                  unsigned long long *result)
+{
+    unsigned long long val;
+    char *p;
+    int err;
+
+    errno = 0;
+    val = strtoull(s, &p, base); /* exempt from syntax-check */
+    err = (memchr(s, '-', p - s) ||
+           errno || (!end_ptr && *p) || p == s);
+    if (end_ptr)
+        *end_ptr = p;
+    if (err)
+        return -1;
+    *result = val;
+    return 0;
+}
+
 int
 virStrToDouble(char const *s,
                char **end_ptr,
index 5b77581aaadb11e83b46e6c6222784e50f0a7c2f..1ed104682c39b413e5750aa03990211b83499c4a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2012 Red Hat, Inc.
+ * Copyright (C) 2007-2014 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -50,6 +50,10 @@ int virStrToLong_ui(char const *s,
                     char **end_ptr,
                     int base,
                     unsigned int *result);
+int virStrToLong_uip(char const *s,
+                     char **end_ptr,
+                     int base,
+                     unsigned int *result);
 int virStrToLong_l(char const *s,
                    char **end_ptr,
                    int base,
@@ -58,6 +62,10 @@ int virStrToLong_ul(char const *s,
                     char **end_ptr,
                     int base,
                     unsigned long *result);
+int virStrToLong_ulp(char const *s,
+                     char **end_ptr,
+                     int base,
+                     unsigned long *result);
 int virStrToLong_ll(char const *s,
                     char **end_ptr,
                     int base,
@@ -66,6 +74,10 @@ int virStrToLong_ull(char const *s,
                      char **end_ptr,
                      int base,
                      unsigned long long *result);
+int virStrToLong_ullp(char const *s,
+                      char **end_ptr,
+                      int base,
+                      unsigned long long *result);
 int virStrToDouble(char const *s,
                    char **end_ptr,
                    double *result);
index 0380df136ead39790c75d033664309e6f550c0cf..1e330f9593f1160cb13d92d629dbcd3a6af57a36 100644 (file)
@@ -408,6 +408,13 @@ testStringToLong(const void *opaque)
     char *end;
     long l;
     unsigned long ul;
+    bool negative;
+
+    if (data->suffix)
+        negative = !!memchr(data->str, '-',
+                            strlen(data->str) - strlen(data->suffix));
+    else
+        negative = !!strchr(data->str, '-');
 
 #define TEST_ONE(Str, Suff, Type, Fn, Fmt, Exp, Exp_ret)                \
     do {                                                                \
@@ -441,6 +448,11 @@ testStringToLong(const void *opaque)
              data->si, data->si_ret);
     TEST_ONE(data->str, data->suffix, unsigned int, ui, "%u",
              data->ui, data->ui_ret);
+    if (negative)
+        TEST_ONE(data->str, data->suffix, unsigned int, uip, "%u", 0U, -1);
+    else
+        TEST_ONE(data->str, data->suffix, unsigned int, uip, "%u",
+                 data->ui, data->ui_ret);
 
     /* We hate adding new API with 'long', and prefer 'int' or 'long
      * long' instead, since platform-specific results are evil */
@@ -450,11 +462,22 @@ testStringToLong(const void *opaque)
     ul = (sizeof(int) == sizeof(long)) ? data->ui : data->ull;
     TEST_ONE(data->str, data->suffix, unsigned long, ul, "%lu",
              ul, (sizeof(int) == sizeof(long)) ? data->ui_ret : data->ull_ret);
+    if (negative)
+        TEST_ONE(data->str, data->suffix, unsigned long, ulp, "%lu", 0UL, -1);
+    else
+        TEST_ONE(data->str, data->suffix, unsigned long, ulp, "%lu", ul,
+                 (sizeof(int) == sizeof(long)) ? data->ui_ret : data->ull_ret);
 
     TEST_ONE(data->str, data->suffix, long long, ll, "%lld",
              data->ll, data->ll_ret);
     TEST_ONE(data->str, data->suffix, unsigned long long, ull, "%llu",
              data->ull, data->ull_ret);
+    if (negative)
+        TEST_ONE(data->str, data->suffix, unsigned long long, ullp, "%llu",
+                 0ULL, -1);
+    else
+        TEST_ONE(data->str, data->suffix, unsigned long long, ullp, "%llu",
+                 data->ull, data->ull_ret);
 
 #undef TEST_ONE