pa_atou(), pa_atol() and pa_atod() are stricter than the libc counterparts (the PA functions reject strings that have trailing extra stuff in them). I have been under the impression that the PA functions only accept "obviously valid numbers", that is, I have assumed that these would be rejected: " 42" (leading whitespace), "" (empty string) and "-18446744073709551615" in case of pa_atou(). I noticed that empty strings are accepted, however, and on closer inspection I found that leading whitespace is accepted too, and even that pa_atou() thinks that "-18446744073709551615" is the same thing as "1"! This patch makes the parsing functions more strict, so that they indeed only accept "obviously valid numbers". In case of pa_atou() I decided to also disallow a leading plus sign, as it's redundant, and looks very strange (i.e. not obviously valid) in contexts where the number represents, for example, an array index. --- src/pulsecore/core-util.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 9b16936..e20ebcb 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -2315,10 +2315,27 @@ int pa_atou(const char *s, uint32_t *ret_u) { pa_assert(s); pa_assert(ret_u); + /* strtoul() ignores leading spaces. We don't. */ + if (isspace(*s)) { + errno = EINVAL; + return -1; + } + + /* strtoul() accepts strings that start with a minus sign. In that case the + * original negative number gets negated, and strtoul() returns the negated + * result. We don't want that kind of behaviour. strtoul() also allows a + * leading plus sign, which is also a thing that we don't want. */ + if (*s == '-' || *s == '+') { + errno = EINVAL; + return -1; + } + errno = 0; l = strtoul(s, &x, 0); - if (!x || *x || errno) { + /* If x doesn't point to the end of s, there was some trailing garbage in + * the string. If x points to s, no conversion was done (empty string). */ + if (!x || *x || x == s || errno) { if (!errno) errno = EINVAL; return -1; @@ -2342,10 +2359,19 @@ int pa_atol(const char *s, long *ret_l) { pa_assert(s); pa_assert(ret_l); + /* strtol() ignores leading spaces. We don't. */ + if (isspace(*s)) { + errno = EINVAL; + return -1; + } + errno = 0; l = strtol(s, &x, 0); - if (!x || *x || errno) { + /* If x doesn't point to the end of s, there was some trailing garbage in + * the string. If x points to s, no conversion was done (at least an empty + * string can trigger this). */ + if (!x || *x || x == s || errno) { if (!errno) errno = EINVAL; return -1; @@ -2371,6 +2397,12 @@ int pa_atod(const char *s, double *ret_d) { pa_assert(s); pa_assert(ret_d); + /* strtod() ignores leading spaces. We don't. */ + if (isspace(*s)) { + errno = EINVAL; + return -1; + } + /* This should be locale independent */ #ifdef HAVE_STRTOF_L @@ -2392,7 +2424,10 @@ int pa_atod(const char *s, double *ret_d) { f = strtod(s, &x); } - if (!x || *x || errno) { + /* If x doesn't point to the end of s, there was some trailing garbage in + * the string. If x points to s, no conversion was done (at least an empty + * string can trigger this). */ + if (!x || *x || x == s || errno) { if (!errno) errno = EINVAL; return -1; -- 1.9.3