|
17 | 17 |
|
18 | 18 | #include "absl/debugging/internal/demangle.h" |
19 | 19 |
|
| 20 | +#include <algorithm> |
20 | 21 | #include <cstddef> |
21 | 22 | #include <cstdint> |
22 | 23 | #include <cstdio> |
@@ -456,22 +457,35 @@ static bool ZeroOrMore(ParseFunc parse_func, State *state) { |
456 | 457 | } |
457 | 458 |
|
458 | 459 | // Append "str" at "out_cur_idx". If there is an overflow, out_cur_idx is |
459 | | -// set to out_end_idx+1. The output string is ensured to |
460 | | -// always terminate with '\0' as long as there is no overflow. |
| 460 | +// set to out_end_idx+1. The output buffer is always terminated with '\0' if it |
| 461 | +// has nonzero length. |
461 | 462 | static void Append(State *state, const char *const str, const size_t length) { |
462 | | - for (size_t i = 0; i < length; ++i) { |
463 | | - if (state->parse_state.out_cur_idx + 1 < |
464 | | - state->out_end_idx) { // +1 for '\0' |
465 | | - state->out[state->parse_state.out_cur_idx++] = str[i]; |
466 | | - } else { |
467 | | - // signal overflow |
468 | | - state->parse_state.out_cur_idx = state->out_end_idx + 1; |
469 | | - break; |
470 | | - } |
| 463 | + if (length == 0) { |
| 464 | + return; |
| 465 | + } |
| 466 | + |
| 467 | + // Figure out how much space is remaining in the output buffer to copy into. |
| 468 | + const int cap = state->out_end_idx - state->parse_state.out_cur_idx; |
| 469 | + |
| 470 | + // If overflow was already signaled (negative value, set further below) or |
| 471 | + // there is zero space to write into, we cannot do anything. |
| 472 | + if (cap <= 0) { |
| 473 | + return; |
471 | 474 | } |
472 | | - if (state->parse_state.out_cur_idx < state->out_end_idx) { |
473 | | - state->out[state->parse_state.out_cur_idx] = |
474 | | - '\0'; // Terminate it with '\0' |
| 475 | + |
| 476 | + // Copy the number of characters requested, capped by the amount of space |
| 477 | + // remaining. |
| 478 | + std::char_traits<char>::copy(state->out + state->parse_state.out_cur_idx, str, |
| 479 | + (std::min)(length, static_cast<size_t>(cap))); |
| 480 | + |
| 481 | + // Did we copy everything we needed to, with enough room to NUL-terminate? |
| 482 | + if (length < static_cast<size_t>(cap)) { |
| 483 | + state->parse_state.out_cur_idx += static_cast<int>(length); |
| 484 | + state->out[state->parse_state.out_cur_idx] = '\0'; |
| 485 | + } else { |
| 486 | + // No, we ran out of space. Signal overflow, and NUL-terminate for safety. |
| 487 | + state->parse_state.out_cur_idx = state->out_end_idx + 1; |
| 488 | + state->out[state->out_end_idx - 1] = '\0'; |
475 | 489 | } |
476 | 490 | } |
477 | 491 |
|
@@ -893,8 +907,11 @@ static bool ParseAbiTags(State *state) { |
893 | 907 | ComplexityGuard guard(state); |
894 | 908 | if (guard.IsTooComplex()) return false; |
895 | 909 |
|
896 | | - while (ParseOneCharToken(state, 'B')) { |
897 | | - ParseState copy = state->parse_state; |
| 910 | + for (;;) { |
| 911 | + const ParseState copy = state->parse_state; |
| 912 | + if (!ParseOneCharToken(state, 'B')) { |
| 913 | + break; |
| 914 | + } |
898 | 915 | MaybeAppend(state, "[abi:"); |
899 | 916 |
|
900 | 917 | if (!ParseSourceName(state)) { |
|
0 commit comments