Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lib/string_helpers.c: refactor string_escape_mem

When printf is given the format specifier %pE, it needs a way of obtaining
the total output size that would be generated if the buffer was large
enough, and string_escape_mem doesn't easily provide that. This is a
refactorization of string_escape_mem in preparation of changing its
external API to provide that information.

The somewhat ugly early returns and subsequent seemingly redundant
conditionals are to make the following patch touch as little as possible
in string_helpers.c while still preserving the current behaviour of never
outputting partial escape sequences. That behaviour must also change for
%pE to work as one expects from every other printf specifier.

Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Rasmus Villemoes and committed by
Linus Torvalds
3aeddc7d 9c98f235

+103 -101
+103 -101
lib/string_helpers.c
··· 239 239 } 240 240 EXPORT_SYMBOL(string_unescape); 241 241 242 - static int escape_passthrough(unsigned char c, char **dst, size_t *osz) 242 + static bool escape_passthrough(unsigned char c, char **dst, char *end) 243 243 { 244 244 char *out = *dst; 245 245 246 - if (*osz < 1) 247 - return -ENOMEM; 248 - 249 - *out++ = c; 250 - 251 - *dst = out; 252 - *osz -= 1; 253 - 254 - return 1; 246 + if (out < end) 247 + *out = c; 248 + *dst = out + 1; 249 + return true; 255 250 } 256 251 257 - static int escape_space(unsigned char c, char **dst, size_t *osz) 252 + static bool escape_space(unsigned char c, char **dst, char *end) 258 253 { 259 254 char *out = *dst; 260 255 unsigned char to; 261 - 262 - if (*osz < 2) 263 - return -ENOMEM; 264 256 265 257 switch (c) { 266 258 case '\n': ··· 271 279 to = 'f'; 272 280 break; 273 281 default: 274 - return 0; 282 + return false; 275 283 } 276 284 277 - *out++ = '\\'; 278 - *out++ = to; 285 + if (out + 2 > end) { 286 + *dst = out + 2; 287 + return true; 288 + } 289 + 290 + if (out < end) 291 + *out = '\\'; 292 + ++out; 293 + if (out < end) 294 + *out = to; 295 + ++out; 279 296 280 297 *dst = out; 281 - *osz -= 2; 282 - 283 - return 1; 298 + return true; 284 299 } 285 300 286 - static int escape_special(unsigned char c, char **dst, size_t *osz) 301 + static bool escape_special(unsigned char c, char **dst, char *end) 287 302 { 288 303 char *out = *dst; 289 304 unsigned char to; 290 - 291 - if (*osz < 2) 292 - return -ENOMEM; 293 305 294 306 switch (c) { 295 307 case '\\': ··· 306 310 to = 'e'; 307 311 break; 308 312 default: 309 - return 0; 313 + return false; 310 314 } 311 315 312 - *out++ = '\\'; 313 - *out++ = to; 316 + if (out + 2 > end) { 317 + *dst = out + 2; 318 + return true; 319 + } 320 + 321 + if (out < end) 322 + *out = '\\'; 323 + ++out; 324 + if (out < end) 325 + *out = to; 326 + ++out; 314 327 315 328 *dst = out; 316 - *osz -= 2; 317 - 318 - return 1; 329 + return true; 319 330 } 320 331 321 - static int escape_null(unsigned char c, char **dst, size_t *osz) 332 + static bool escape_null(unsigned char c, char **dst, char *end) 322 333 { 323 334 char *out = *dst; 324 - 325 - if (*osz < 2) 326 - return -ENOMEM; 327 335 328 336 if (c) 329 - return 0; 337 + return false; 330 338 331 - *out++ = '\\'; 332 - *out++ = '0'; 339 + if (out + 2 > end) { 340 + *dst = out + 2; 341 + return true; 342 + } 343 + 344 + if (out < end) 345 + *out = '\\'; 346 + ++out; 347 + if (out < end) 348 + *out = '0'; 349 + ++out; 333 350 334 351 *dst = out; 335 - *osz -= 2; 336 - 337 - return 1; 352 + return true; 338 353 } 339 354 340 - static int escape_octal(unsigned char c, char **dst, size_t *osz) 355 + static bool escape_octal(unsigned char c, char **dst, char *end) 341 356 { 342 357 char *out = *dst; 343 358 344 - if (*osz < 4) 345 - return -ENOMEM; 359 + if (out + 4 > end) { 360 + *dst = out + 4; 361 + return true; 362 + } 346 363 347 - *out++ = '\\'; 348 - *out++ = ((c >> 6) & 0x07) + '0'; 349 - *out++ = ((c >> 3) & 0x07) + '0'; 350 - *out++ = ((c >> 0) & 0x07) + '0'; 364 + if (out < end) 365 + *out = '\\'; 366 + ++out; 367 + if (out < end) 368 + *out = ((c >> 6) & 0x07) + '0'; 369 + ++out; 370 + if (out < end) 371 + *out = ((c >> 3) & 0x07) + '0'; 372 + ++out; 373 + if (out < end) 374 + *out = ((c >> 0) & 0x07) + '0'; 375 + ++out; 351 376 352 377 *dst = out; 353 - *osz -= 4; 354 - 355 - return 1; 378 + return true; 356 379 } 357 380 358 - static int escape_hex(unsigned char c, char **dst, size_t *osz) 381 + static bool escape_hex(unsigned char c, char **dst, char *end) 359 382 { 360 383 char *out = *dst; 361 384 362 - if (*osz < 4) 363 - return -ENOMEM; 385 + if (out + 4 > end) { 386 + *dst = out + 4; 387 + return true; 388 + } 364 389 365 - *out++ = '\\'; 366 - *out++ = 'x'; 367 - *out++ = hex_asc_hi(c); 368 - *out++ = hex_asc_lo(c); 390 + if (out < end) 391 + *out = '\\'; 392 + ++out; 393 + if (out < end) 394 + *out = 'x'; 395 + ++out; 396 + if (out < end) 397 + *out = hex_asc_hi(c); 398 + ++out; 399 + if (out < end) 400 + *out = hex_asc_lo(c); 401 + ++out; 369 402 370 403 *dst = out; 371 - *osz -= 4; 372 - 373 - return 1; 404 + return true; 374 405 } 375 406 376 407 /** ··· 459 436 int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz, 460 437 unsigned int flags, const char *esc) 461 438 { 462 - char *out = *dst, *p = out; 439 + char *p = *dst; 440 + char *end = p + osz; 463 441 bool is_dict = esc && *esc; 464 - int ret = 0; 442 + int ret; 465 443 466 444 while (isz--) { 467 445 unsigned char c = *src++; ··· 482 458 (is_dict && !strchr(esc, c))) { 483 459 /* do nothing */ 484 460 } else { 485 - if (flags & ESCAPE_SPACE) { 486 - ret = escape_space(c, &p, &osz); 487 - if (ret < 0) 488 - break; 489 - if (ret > 0) 490 - continue; 491 - } 461 + if (flags & ESCAPE_SPACE && escape_space(c, &p, end)) 462 + continue; 492 463 493 - if (flags & ESCAPE_SPECIAL) { 494 - ret = escape_special(c, &p, &osz); 495 - if (ret < 0) 496 - break; 497 - if (ret > 0) 498 - continue; 499 - } 464 + if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end)) 465 + continue; 500 466 501 - if (flags & ESCAPE_NULL) { 502 - ret = escape_null(c, &p, &osz); 503 - if (ret < 0) 504 - break; 505 - if (ret > 0) 506 - continue; 507 - } 467 + if (flags & ESCAPE_NULL && escape_null(c, &p, end)) 468 + continue; 508 469 509 470 /* ESCAPE_OCTAL and ESCAPE_HEX always go last */ 510 - if (flags & ESCAPE_OCTAL) { 511 - ret = escape_octal(c, &p, &osz); 512 - if (ret < 0) 513 - break; 471 + if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end)) 514 472 continue; 515 - } 516 - if (flags & ESCAPE_HEX) { 517 - ret = escape_hex(c, &p, &osz); 518 - if (ret < 0) 519 - break; 473 + 474 + if (flags & ESCAPE_HEX && escape_hex(c, &p, end)) 520 475 continue; 521 - } 522 476 } 523 477 524 - ret = escape_passthrough(c, &p, &osz); 525 - if (ret < 0) 526 - break; 478 + escape_passthrough(c, &p, end); 527 479 } 528 480 481 + if (p > end) { 482 + *dst = end; 483 + return -ENOMEM; 484 + } 485 + 486 + ret = p - *dst; 529 487 *dst = p; 530 - 531 - if (ret < 0) 532 - return ret; 533 - 534 - return p - out; 488 + return ret; 535 489 } 536 490 EXPORT_SYMBOL(string_escape_mem);