uri_normalizer_fragment_encode() used istcat() to append the text between two '#' characters, and istcat() copies one byte at a time. A URI without any fragment is therefore copied byte by byte in full.
Copy each run in one memcpy() instead, and check the remaining room up front rather than relying on istcat() to detect the overflow. istcat() copies as much as fits before returning an error, but the caller discards the output on error, so checking first is equivalent. Each '#' expands to "%23", which is why the check adds three bytes for a run that ends on one. Verified by running the old and the new implementation over the same inputs with every destination size from zero to past the truncation point, comparing both the output and the returned error code: 119898 cases, no difference. This is a pure optimization with no functional change, so the risk of regression is low. It is not needed in stable branches. Signed-off-by: Youngkwang Lee <[email protected]> --- src/uri_normalizer.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/uri_normalizer.c b/src/uri_normalizer.c index cb67d56f0..1a7654120 100644 --- a/src/uri_normalizer.c +++ b/src/uri_normalizer.c @@ -30,17 +30,23 @@ enum uri_normalizer_err uri_normalizer_fragment_encode(const struct ist input, s while (istlen(scanner)) { const struct ist before_hash = istsplit(&scanner, '#'); + const int encode = (istend(before_hash) != istend(scanner)); - if (istcat(&output, before_hash, size) < 0) { + /* Everything up to the '#' is copied verbatim, so it can be + * copied in one go rather than one byte at a time. Each '#' + * grows by two bytes, hence the check for three below. + */ + if (istlen(output) + istlen(before_hash) + (encode ? 3 : 0) > size) { err = URI_NORMALIZER_ERR_ALLOC; goto fail; } - if (istend(before_hash) != istend(scanner)) { - if (istcat(&output, ist("%23"), size) < 0) { - err = URI_NORMALIZER_ERR_ALLOC; - goto fail; - } + memcpy(istend(output), istptr(before_hash), istlen(before_hash)); + output = ist2(istptr(output), istlen(output) + istlen(before_hash)); + + if (encode) { + memcpy(istend(output), "%23", 3); + output = ist2(istptr(output), istlen(output) + 3); } } -- 2.45.1

