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.
Unified · Split
| @@ -246,13 +246,17 @@ EXPORT_SYMBOL(strlcat); · 245 unmodified lines | ||
| 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 |
| @@ -266,14 +270,18 @@ EXPORT_SYMBOL(strcmp); · 7 unmodified lines | ||
| 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 |