Commit a414f01ac2899f273ef8fe98fa44158ac12793f2
1 parent
6602b355c2
Exists in
master
and in
7 other branches
strcmp: fix overflow and possibly signedness error
Doing the strcmp return value as signed char __res = *cs - *ct; is wrong for two reasons. The subtraction can overflow because __res doesn't use a type big enough. Moreover the compared bytes should be interpreted as unsigned char as specified by POSIX. The same problem is fixed in strncmp. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Cc: Michael Buesch <mb@bu3sch.de> Cc: Andreas Schwab <schwab@linux-m68k.org> Cc: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 14 additions and 6 deletions Side-by-side Diff
lib/string.c
... | ... | @@ -246,13 +246,17 @@ |
246 | 246 | #undef strcmp |
247 | 247 | int strcmp(const char *cs, const char *ct) |
248 | 248 | { |
249 | - signed char __res; | |
249 | + unsigned char c1, c2; | |
250 | 250 | |
251 | 251 | while (1) { |
252 | - if ((__res = *cs - *ct++) != 0 || !*cs++) | |
252 | + c1 = *cs++; | |
253 | + c2 = *ct++; | |
254 | + if (c1 != c2) | |
255 | + return c1 < c2 ? -1 : 1; | |
256 | + if (!c1) | |
253 | 257 | break; |
254 | 258 | } |
255 | - return __res; | |
259 | + return 0; | |
256 | 260 | } |
257 | 261 | EXPORT_SYMBOL(strcmp); |
258 | 262 | #endif |
259 | 263 | |
260 | 264 | |
... | ... | @@ -266,14 +270,18 @@ |
266 | 270 | */ |
267 | 271 | int strncmp(const char *cs, const char *ct, size_t count) |
268 | 272 | { |
269 | - signed char __res = 0; | |
273 | + unsigned char c1, c2; | |
270 | 274 | |
271 | 275 | while (count) { |
272 | - if ((__res = *cs - *ct++) != 0 || !*cs++) | |
276 | + c1 = *cs++; | |
277 | + c2 = *ct++; | |
278 | + if (c1 != c2) | |
279 | + return c1 < c2 ? -1 : 1; | |
280 | + if (!c1) | |
273 | 281 | break; |
274 | 282 | count--; |
275 | 283 | } |
276 | - return __res; | |
284 | + return 0; | |
277 | 285 | } |
278 | 286 | EXPORT_SYMBOL(strncmp); |
279 | 287 | #endif |