Fix dissect leading delimiter byte offset for multi-byte characters#22444
Fix dissect leading delimiter byte offset for multi-byte characters#22444winklemad wants to merge 1 commit into
Conversation
PR Reviewer Guide 🔍(Review updated until commit 7f400dd)Here are some key observations to aid the review process:
|
PR Code Suggestions ✨Latest suggestions up to 7f400dd Explore these optional code suggestions:
Previous suggestionsSuggestions up to commit 7f23336
Suggestions up to commit 54ac7cf
|
54ac7cf to
7f23336
Compare
|
Persistent review updated to latest commit 7f23336 |
DissectParser seeds the value cursor with leadingDelimiter.length(), a char count, but uses it to index into the input byte array (inputString.getBytes(UTF_8)). When the leading delimiter contains a non-ASCII character its char length is smaller than its byte length, so the first value starts partway into the delimiter's bytes and comes back corrupted rather than throwing. Between-key delimiters in the same method already measure in bytes; measure the leading delimiter in bytes too. Signed-off-by: winklemad <winklemad@outlook.com>
7f23336 to
7f400dd
Compare
|
Persistent review updated to latest commit 7f400dd |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #22444 +/- ##
============================================
+ Coverage 73.46% 73.51% +0.04%
- Complexity 76477 76555 +78
============================================
Files 6104 6104
Lines 346568 346569 +1
Branches 49883 49883
============================================
+ Hits 254598 254766 +168
+ Misses 71693 71526 -167
Partials 20277 20277 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Description
DissectParser.parseseeds the value cursor withleadingDelimiter.length()— a char count — but uses it to index into theinputbyte array (input = inputString.getBytes(UTF_8)). When the leading delimiter contains a non-ASCII character its char length is smaller than its byte length, so the first value starts partway into the delimiter's bytes and comes back corrupted. Nothing is thrown — it silently returns the wrong value.Example — pattern
»%{a}, input»foo(»= U+00BB = 2 bytes):leadingDelimiter.length()is1, sovalueStart = 1— one byte into the 2-byte».copyOfRange(input, 1, …)=[BB, 66, 6F, 6F], which decodes to"�foo".{a="�foo"}; expected{a="foo"}.Root cause. The between-key delimiters in the same method are already handled in the byte domain —
delimiter = dissectPair.getDelimiter().getBytes(UTF_8), indexed againstinput.length. Only the leading delimiter measured its offset withString.length().testLogstashSpecsalready relies on multi-byte between-key delimiters (»,€) working, so multi-byte delimiters are a supported case — the leading position was just overlooked.Fix. Measure the leading delimiter in bytes, matching the rest of the method:
One line;
StandardCharsetsis already imported. This is the only place inparsewhere a char length indexed the byte array — lines 137/221/222 operate onStrings in the char domain and are correct. Reachable via thedissectingest processor with any pattern whose leading delimiter contains a non-ASCII character.Test. Added
testLeadingDelimiterMultiBytenext to the existingtestLeadingDelimiter, covering 2-byte (»), 3-byte (€,子) and 4-byte / surrogate-pair (😀) leading delimiters, single and multiple keys, a repeated delimiter, and a multi-byte value. It fails before the fix (Expected: "foo" but: was "�foo") and passes after. The:libs:opensearch-dissecttest suite plusprecommit(spotless, checkstyle, forbiddenApis, licenseHeaders) are green locally.Related Issues
No linked issue — found by reading the code.
Check List
--signoff.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.