diff mbox

[PULL,44/44] cutils: work around platform differences in strto{l, ul, ll, ull}

Message ID 1442241198-11235-2-git-send-email-pbonzini@redhat.com
State New
Headers show

Commit Message

Paolo Bonzini Sept. 14, 2015, 2:33 p.m. UTC
Linux returns 0 if no conversion was made, while OS X and presumably
the BSDs return EINVAL.  The OS X convention rejects more invalid
inputs, so convert to it and adjust the test case.

Windows returns 1 from strtoul and strtoull (instead of -1) for
negative out-of-range input; fix it up.

Reported-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/test-cutils.c | 57 +++++++++++++++--------------------------------------
 util/cutils.c       | 24 +++++++++++++++++-----
 2 files changed, 35 insertions(+), 46 deletions(-)

Comments

Peter Maydell Sept. 14, 2015, 2:47 p.m. UTC | #1
On 14 September 2015 at 15:33, Paolo Bonzini <pbonzini@redhat.com> wrote:
> Linux returns 0 if no conversion was made, while OS X and presumably
> the BSDs return EINVAL.  The OS X convention rejects more invalid
> inputs, so convert to it and adjust the test case.
>
> Windows returns 1 from strtoul and strtoull (instead of -1) for
> negative out-of-range input; fix it up.
>
> Reported-by: Peter Maydell <peter.maydell@linaro.org>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  tests/test-cutils.c | 57 +++++++++++++++--------------------------------------
>  util/cutils.c       | 24 +++++++++++++++++-----
>  2 files changed, 35 insertions(+), 46 deletions(-)
>
> diff --git a/tests/test-cutils.c b/tests/test-cutils.c
> index a7a15a5..0046c61 100644
> --- a/tests/test-cutils.c
> +++ b/tests/test-cutils.c
> @@ -264,9 +264,7 @@ static void test_qemu_strtol_empty(void)
>
>      err = qemu_strtol(str, &endptr, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert_cmpint(res, ==, 0);
> -    g_assert(endptr == str);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtol_whitespace(void)
> @@ -279,9 +277,7 @@ static void test_qemu_strtol_whitespace(void)
>
>      err = qemu_strtol(str, &endptr, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert_cmpint(res, ==, 0);
> -    g_assert(endptr == str);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtol_invalid(void)
> @@ -294,9 +290,7 @@ static void test_qemu_strtol_invalid(void)
>
>      err = qemu_strtol(str, &endptr, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert_cmpint(res, ==, 0);
> -    g_assert(endptr == str);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtol_trailing(void)
> @@ -478,8 +472,7 @@ static void test_qemu_strtol_full_empty(void)
>
>      err =  qemu_strtol(str, NULL, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert_cmpint(res, ==, 0);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtol_full_negative(void)
> @@ -555,9 +548,7 @@ static void test_qemu_strtoul_empty(void)
>
>      err = qemu_strtoul(str, &endptr, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert_cmpint(res, ==, 0);
> -    g_assert(endptr == str);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtoul_whitespace(void)
> @@ -570,9 +561,7 @@ static void test_qemu_strtoul_whitespace(void)
>
>      err = qemu_strtoul(str, &endptr, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert_cmpint(res, ==, 0);
> -    g_assert(endptr == str);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtoul_invalid(void)
> @@ -585,8 +574,7 @@ static void test_qemu_strtoul_invalid(void)
>
>      err = qemu_strtoul(str, &endptr, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert(endptr == str);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtoul_trailing(void)
> @@ -765,8 +753,7 @@ static void test_qemu_strtoul_full_empty(void)
>
>      err = qemu_strtoul(str, NULL, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert_cmpint(res, ==, 0);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>  static void test_qemu_strtoul_full_negative(void)
>  {
> @@ -840,9 +827,7 @@ static void test_qemu_strtoll_empty(void)
>
>      err = qemu_strtoll(str, &endptr, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert_cmpint(res, ==, 0);
> -    g_assert(endptr == str);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtoll_whitespace(void)
> @@ -855,9 +840,7 @@ static void test_qemu_strtoll_whitespace(void)
>
>      err = qemu_strtoll(str, &endptr, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert_cmpint(res, ==, 0);
> -    g_assert(endptr == str);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtoll_invalid(void)
> @@ -870,8 +853,7 @@ static void test_qemu_strtoll_invalid(void)
>
>      err = qemu_strtoll(str, &endptr, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert(endptr == str);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtoll_trailing(void)
> @@ -1050,8 +1032,7 @@ static void test_qemu_strtoll_full_empty(void)
>
>      err = qemu_strtoll(str, NULL, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert_cmpint(res, ==, 0);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtoll_full_negative(void)
> @@ -1128,9 +1109,7 @@ static void test_qemu_strtoull_empty(void)
>
>      err = qemu_strtoull(str, &endptr, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert_cmpint(res, ==, 0);
> -    g_assert(endptr == str);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtoull_whitespace(void)
> @@ -1143,9 +1122,7 @@ static void test_qemu_strtoull_whitespace(void)
>
>      err = qemu_strtoull(str, &endptr, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert_cmpint(res, ==, 0);
> -    g_assert(endptr == str);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtoull_invalid(void)
> @@ -1158,8 +1135,7 @@ static void test_qemu_strtoull_invalid(void)
>
>      err = qemu_strtoull(str, &endptr, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert(endptr == str);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtoull_trailing(void)
> @@ -1338,8 +1314,7 @@ static void test_qemu_strtoull_full_empty(void)
>
>      err = qemu_strtoull(str, NULL, 0, &res);
>
> -    g_assert_cmpint(err, ==, 0);
> -    g_assert_cmpint(res, ==, 0);
> +    g_assert_cmpint(err, ==, -EINVAL);
>  }
>
>  static void test_qemu_strtoull_full_negative(void)
> diff --git a/util/cutils.c b/util/cutils.c
> index 67c50e5..84ceaff 100644
> --- a/util/cutils.c
> +++ b/util/cutils.c
> @@ -361,9 +361,15 @@ int64_t strtosz(const char *nptr, char **end)
>  /**
>   * Helper function for qemu_strto*l() functions.
>   */
> -static int check_strtox_error(const char **next, char *endptr,
> +static int check_strtox_error(const char *p, char *endptr, const char **next,
>                                int err)
>  {
> +    /* If no conversion was performed, prefer BSD behavior over glibc
> +     * behavior.
> +     */
> +    if (err == 0 && endptr == p) {
> +        err = EINVAL;
> +    }
>      if (!next && *endptr) {
>          return -EINVAL;
>      }
> @@ -412,7 +418,7 @@ int qemu_strtol(const char *nptr, const char **endptr, int base,
>      } else {
>          errno = 0;
>          *result = strtol(nptr, &p, base);
> -        err = check_strtox_error(endptr, p, errno);
> +        err = check_strtox_error(nptr, p, endptr, errno);
>      }
>      return err;
>  }
> @@ -443,7 +449,11 @@ int qemu_strtoul(const char *nptr, const char **endptr, int base,
>      } else {
>          errno = 0;
>          *result = strtoul(nptr, &p, base);
> -        err = check_strtox_error(endptr, p, errno);
> +        /* Windows returns 1 for negative out-of-range values.  */
> +        if (errno == ERANGE) {
> +            *result = -1;
> +        }
> +        err = check_strtox_error(nptr, p, endptr, errno);
>      }
>      return err;
>  }
> @@ -466,7 +476,7 @@ int qemu_strtoll(const char *nptr, const char **endptr, int base,
>      } else {
>          errno = 0;
>          *result = strtoll(nptr, &p, base);
> -        err = check_strtox_error(endptr, p, errno);
> +        err = check_strtox_error(nptr, p, endptr, errno);
>      }
>      return err;
>  }
> @@ -489,7 +499,11 @@ int qemu_strtoull(const char *nptr, const char **endptr, int base,
>      } else {
>          errno = 0;
>          *result = strtoull(nptr, &p, base);
> -        err = check_strtox_error(endptr, p, errno);
> +        /* Windows returns 1 for negative out-of-range values.  */
> +        if (errno == ERANGE) {
> +            *result = -1;
> +        }
> +        err = check_strtox_error(nptr, p, endptr, errno);
>      }
>      return err;
>  }
> --
> 2.5.0
>
>
Peter Maydell Sept. 14, 2015, 2:48 p.m. UTC | #2
On 14 September 2015 at 15:47, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 14 September 2015 at 15:33, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> Windows returns 1 from strtoul and strtoull (instead of -1) for
>> negative out-of-range input; fix it up.

No problem with this patch, just wanted to say 'wat?' at this.

(and then fumbled a blank reply with my mail client, oh well)

-- PMM
Paolo Bonzini Sept. 14, 2015, 3 p.m. UTC | #3
On 14/09/2015 16:48, Peter Maydell wrote:
>>> Windows returns 1 from strtoul and strtoull (instead of -1) for
>>> >> negative out-of-range input; fix it up.
> No problem with this patch, just wanted to say 'wat?' at this.

Indeed.  I only tested with Wine, but it cannot be a mistake:
http://marc.info/?l=wine-patches&m=138011287312090&w=2

There are even test cases. :-)

Paolo
diff mbox

Patch

diff --git a/tests/test-cutils.c b/tests/test-cutils.c
index a7a15a5..0046c61 100644
--- a/tests/test-cutils.c
+++ b/tests/test-cutils.c
@@ -264,9 +264,7 @@  static void test_qemu_strtol_empty(void)
 
     err = qemu_strtol(str, &endptr, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, 0);
-    g_assert(endptr == str);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtol_whitespace(void)
@@ -279,9 +277,7 @@  static void test_qemu_strtol_whitespace(void)
 
     err = qemu_strtol(str, &endptr, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, 0);
-    g_assert(endptr == str);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtol_invalid(void)
@@ -294,9 +290,7 @@  static void test_qemu_strtol_invalid(void)
 
     err = qemu_strtol(str, &endptr, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, 0);
-    g_assert(endptr == str);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtol_trailing(void)
@@ -478,8 +472,7 @@  static void test_qemu_strtol_full_empty(void)
 
     err =  qemu_strtol(str, NULL, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, 0);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtol_full_negative(void)
@@ -555,9 +548,7 @@  static void test_qemu_strtoul_empty(void)
 
     err = qemu_strtoul(str, &endptr, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, 0);
-    g_assert(endptr == str);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtoul_whitespace(void)
@@ -570,9 +561,7 @@  static void test_qemu_strtoul_whitespace(void)
 
     err = qemu_strtoul(str, &endptr, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, 0);
-    g_assert(endptr == str);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtoul_invalid(void)
@@ -585,8 +574,7 @@  static void test_qemu_strtoul_invalid(void)
 
     err = qemu_strtoul(str, &endptr, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert(endptr == str);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtoul_trailing(void)
@@ -765,8 +753,7 @@  static void test_qemu_strtoul_full_empty(void)
 
     err = qemu_strtoul(str, NULL, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, 0);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 static void test_qemu_strtoul_full_negative(void)
 {
@@ -840,9 +827,7 @@  static void test_qemu_strtoll_empty(void)
 
     err = qemu_strtoll(str, &endptr, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, 0);
-    g_assert(endptr == str);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtoll_whitespace(void)
@@ -855,9 +840,7 @@  static void test_qemu_strtoll_whitespace(void)
 
     err = qemu_strtoll(str, &endptr, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, 0);
-    g_assert(endptr == str);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtoll_invalid(void)
@@ -870,8 +853,7 @@  static void test_qemu_strtoll_invalid(void)
 
     err = qemu_strtoll(str, &endptr, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert(endptr == str);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtoll_trailing(void)
@@ -1050,8 +1032,7 @@  static void test_qemu_strtoll_full_empty(void)
 
     err = qemu_strtoll(str, NULL, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, 0);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtoll_full_negative(void)
@@ -1128,9 +1109,7 @@  static void test_qemu_strtoull_empty(void)
 
     err = qemu_strtoull(str, &endptr, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, 0);
-    g_assert(endptr == str);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtoull_whitespace(void)
@@ -1143,9 +1122,7 @@  static void test_qemu_strtoull_whitespace(void)
 
     err = qemu_strtoull(str, &endptr, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, 0);
-    g_assert(endptr == str);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtoull_invalid(void)
@@ -1158,8 +1135,7 @@  static void test_qemu_strtoull_invalid(void)
 
     err = qemu_strtoull(str, &endptr, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert(endptr == str);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtoull_trailing(void)
@@ -1338,8 +1314,7 @@  static void test_qemu_strtoull_full_empty(void)
 
     err = qemu_strtoull(str, NULL, 0, &res);
 
-    g_assert_cmpint(err, ==, 0);
-    g_assert_cmpint(res, ==, 0);
+    g_assert_cmpint(err, ==, -EINVAL);
 }
 
 static void test_qemu_strtoull_full_negative(void)
diff --git a/util/cutils.c b/util/cutils.c
index 67c50e5..84ceaff 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -361,9 +361,15 @@  int64_t strtosz(const char *nptr, char **end)
 /**
  * Helper function for qemu_strto*l() functions.
  */
-static int check_strtox_error(const char **next, char *endptr,
+static int check_strtox_error(const char *p, char *endptr, const char **next,
                               int err)
 {
+    /* If no conversion was performed, prefer BSD behavior over glibc
+     * behavior.
+     */
+    if (err == 0 && endptr == p) {
+        err = EINVAL;
+    }
     if (!next && *endptr) {
         return -EINVAL;
     }
@@ -412,7 +418,7 @@  int qemu_strtol(const char *nptr, const char **endptr, int base,
     } else {
         errno = 0;
         *result = strtol(nptr, &p, base);
-        err = check_strtox_error(endptr, p, errno);
+        err = check_strtox_error(nptr, p, endptr, errno);
     }
     return err;
 }
@@ -443,7 +449,11 @@  int qemu_strtoul(const char *nptr, const char **endptr, int base,
     } else {
         errno = 0;
         *result = strtoul(nptr, &p, base);
-        err = check_strtox_error(endptr, p, errno);
+        /* Windows returns 1 for negative out-of-range values.  */
+        if (errno == ERANGE) {
+            *result = -1;
+        }
+        err = check_strtox_error(nptr, p, endptr, errno);
     }
     return err;
 }
@@ -466,7 +476,7 @@  int qemu_strtoll(const char *nptr, const char **endptr, int base,
     } else {
         errno = 0;
         *result = strtoll(nptr, &p, base);
-        err = check_strtox_error(endptr, p, errno);
+        err = check_strtox_error(nptr, p, endptr, errno);
     }
     return err;
 }
@@ -489,7 +499,11 @@  int qemu_strtoull(const char *nptr, const char **endptr, int base,
     } else {
         errno = 0;
         *result = strtoull(nptr, &p, base);
-        err = check_strtox_error(endptr, p, errno);
+        /* Windows returns 1 for negative out-of-range values.  */
+        if (errno == ERANGE) {
+            *result = -1;
+        }
+        err = check_strtox_error(nptr, p, endptr, errno);
     }
     return err;
 }