diff options
author | Jan Beulich <JBeulich@suse.com> | 2012-10-04 20:13:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-05 14:04:58 -0400 |
commit | da99075c1d368315e1508b6143226c0d27b621e0 (patch) | |
tree | 1ceefd8dc83bcc569640b519c00b0313be88bf1e /lib/vsprintf.c | |
parent | 214f766ea0909e743122966c4617b3a112e405d7 (diff) |
lib/vsprintf.c: improve standard conformance of sscanf()
Xen's pciback points out a couple of deficiencies with vsscanf()'s
standard conformance:
- Trailing character matching cannot be checked by the caller: With a
format string of "(%x:%x.%x) %n" absence of the closing parenthesis
cannot be checked, as input of "(00:00.0)" doesn't cause the %n to be
evaluated (because of the code not skipping white space before the
trailing %n).
- The parameter corresponding to a trailing %n could get filled even if
there was a matching error: With a format string of "(%x:%x.%x)%n",
input of "(00:00.0]" would still fill the respective variable pointed to
(and hence again make the mismatch non-detectable by the caller).
This patch aims at fixing those, but leaves other non-conforming aspects
of it untouched, among them these possibly relevant ones:
- improper handling of the assignment suppression character '*' (blindly
discarding all succeeding non-white space from the format and input
strings),
- not honoring conversion specifiers for %n, - not recognizing the C99
conversion specifier 't' (recognized by vsprintf()).
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib/vsprintf.c')
-rw-r--r-- | lib/vsprintf.c | 33 |
1 files changed, 14 insertions, 19 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 9287e2549936..39c99fea7c03 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -2017,7 +2017,7 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
2017 | s16 field_width; | 2017 | s16 field_width; |
2018 | bool is_sign; | 2018 | bool is_sign; |
2019 | 2019 | ||
2020 | while (*fmt && *str) { | 2020 | while (*fmt) { |
2021 | /* skip any white space in format */ | 2021 | /* skip any white space in format */ |
2022 | /* white space in format matchs any amount of | 2022 | /* white space in format matchs any amount of |
2023 | * white space, including none, in the input. | 2023 | * white space, including none, in the input. |
@@ -2042,6 +2042,8 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
2042 | * advance both strings to next white space | 2042 | * advance both strings to next white space |
2043 | */ | 2043 | */ |
2044 | if (*fmt == '*') { | 2044 | if (*fmt == '*') { |
2045 | if (!*str) | ||
2046 | break; | ||
2045 | while (!isspace(*fmt) && *fmt != '%' && *fmt) | 2047 | while (!isspace(*fmt) && *fmt != '%' && *fmt) |
2046 | fmt++; | 2048 | fmt++; |
2047 | while (!isspace(*str) && *str) | 2049 | while (!isspace(*str) && *str) |
@@ -2070,7 +2072,17 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
2070 | } | 2072 | } |
2071 | } | 2073 | } |
2072 | 2074 | ||
2073 | if (!*fmt || !*str) | 2075 | if (!*fmt) |
2076 | break; | ||
2077 | |||
2078 | if (*fmt == 'n') { | ||
2079 | /* return number of characters read so far */ | ||
2080 | *va_arg(args, int *) = str - buf; | ||
2081 | ++fmt; | ||
2082 | continue; | ||
2083 | } | ||
2084 | |||
2085 | if (!*str) | ||
2074 | break; | 2086 | break; |
2075 | 2087 | ||
2076 | base = 10; | 2088 | base = 10; |
@@ -2103,13 +2115,6 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
2103 | num++; | 2115 | num++; |
2104 | } | 2116 | } |
2105 | continue; | 2117 | continue; |
2106 | case 'n': | ||
2107 | /* return number of characters read so far */ | ||
2108 | { | ||
2109 | int *i = (int *)va_arg(args, int*); | ||
2110 | *i = str - buf; | ||
2111 | } | ||
2112 | continue; | ||
2113 | case 'o': | 2118 | case 'o': |
2114 | base = 8; | 2119 | base = 8; |
2115 | break; | 2120 | break; |
@@ -2210,16 +2215,6 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
2210 | str = next; | 2215 | str = next; |
2211 | } | 2216 | } |
2212 | 2217 | ||
2213 | /* | ||
2214 | * Now we've come all the way through so either the input string or the | ||
2215 | * format ended. In the former case, there can be a %n at the current | ||
2216 | * position in the format that needs to be filled. | ||
2217 | */ | ||
2218 | if (*fmt == '%' && *(fmt + 1) == 'n') { | ||
2219 | int *p = (int *)va_arg(args, int *); | ||
2220 | *p = str - buf; | ||
2221 | } | ||
2222 | |||
2223 | return num; | 2218 | return num; |
2224 | } | 2219 | } |
2225 | EXPORT_SYMBOL(vsscanf); | 2220 | EXPORT_SYMBOL(vsscanf); |