[pulseaudio-discuss] [PATCH] core-util: Make number parsing stricter
Tanu Kaskinen
tanu.kaskinen at linux.intel.com
Wed Feb 25 01:56:47 PST 2015
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
More information about the pulseaudio-discuss
mailing list