Skip to content

[ML] Better handling of invalid JSON state documents - #2895

Merged
edsavage merged 8 commits into
elastic:mainfrom
edsavage:improve_parsing_json_state
Feb 9, 2026
Merged

[ML] Better handling of invalid JSON state documents#2895
edsavage merged 8 commits into
elastic:mainfrom
edsavage:improve_parsing_json_state

Conversation

@edsavage

@edsavage edsavage commented Jan 26, 2026

Copy link
Copy Markdown
Contributor

Various changes to the handling of errors when parsing JSON state documents to improve consistency and provide better visibility

Relates #2875

Various changes to the handling of errors when parsing JSON state documents to improve consistency and provide better visibility
@prodsecmachine

prodsecmachine commented Jan 26, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@edsavage
edsavage requested a review from valeriy42 January 26, 2026 03:33

@valeriy42 valeriy42 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks mostly good. I have just a few minor comments.

Comment thread lib/core/CStateDecompressor.cc
message = "Encountered NULL character in stream before parsing has started.";
ret = false;
}
if (m_Reader->handler().s_Type == SBoostJsonHandler::E_TokenObjectEnd) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since both if statements could be true, you would potentially reassign message. I guess it should be either else if here, or the messages should be concatenated.

Comment thread lib/api/unittest/CFieldDataCategorizerTest.cc Outdated
Comment thread lib/core/CJsonStateRestoreTraverser.cc

@valeriy42 valeriy42 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@edsavage
edsavage merged commit 1ad9d71 into elastic:main Feb 9, 2026
3 checks passed
edsavage added a commit to edsavage/ml-cpp that referenced this pull request Feb 18, 2026
The isEof() implementation was changed from peek()-based to eof()-based
in elastic#2895, but eof() is a lagging indicator on Windows - it is not set
until a read past the end is attempted. This caused
CFieldDataCategorizerTest/testRestoreFromBadState and
testRestoreStateRecoversWithEmptyState to fail on Windows.

Two fixes:
1. isEof() now falls back to peek() when eof() returns false, making
   the check portable across platforms.
2. The empty array detection in start() no longer depends on isEof()
   at all - the token sequence [,] is sufficient to identify an empty
   array without checking stream state.

Tested on macOS ARM, Linux aarch64, and Windows x86_64 - all 800 tests
pass on all three platforms.

Co-authored-by: Cursor <cursoragent@cursor.com>
edsavage added a commit that referenced this pull request Feb 23, 2026
The isEof() implementation was changed from peek()-based to eof()-based
in #2895, but eof() is a lagging indicator on Windows - it is not set
until a read past the end is attempted. This caused
CFieldDataCategorizerTest/testRestoreFromBadState and
testRestoreStateRecoversWithEmptyState to fail on Windows.

Two fixes:
1. isEof() now falls back to peek() when eof() returns false, making
   the check portable across platforms.
2. The empty array detection in start() no longer depends on isEof()
   at all - the token sequence [,] is sufficient to identify an empty
   array without checking stream state.

Tested on macOS ARM, Linux aarch64, and Windows x86_64 - all tests
pass on all three platforms.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
edsavage added a commit to edsavage/ml-cpp that referenced this pull request Feb 26, 2026
…c#2898)

The isEof() implementation was changed from peek()-based to eof()-based
in elastic#2895, but eof() is a lagging indicator on Windows - it is not set
until a read past the end is attempted. This caused
CFieldDataCategorizerTest/testRestoreFromBadState and
testRestoreStateRecoversWithEmptyState to fail on Windows.

Two fixes:
1. isEof() now falls back to peek() when eof() returns false, making
   the check portable across platforms.
2. The empty array detection in start() no longer depends on isEof()
   at all - the token sequence [,] is sufficient to identify an empty
   array without checking stream state.

Tested on macOS ARM, Linux aarch64, and Windows x86_64 - all tests
pass on all three platforms.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
valeriy42 added a commit that referenced this pull request Jul 22, 2026
…3082)

The LOG_ERROR at readHeader() for missing or empty compressed state
documents was never addressed in #2895 and is redundant with parseNext()
diagnostics. Downgrade to INFO so routine categorizer state restore
misses no longer trip the serverless ERROR log-rate promotion gate.

Relates #2875
github-actions Bot added a commit that referenced this pull request Jul 24, 2026
…3082) (#3093)

The LOG_ERROR at readHeader() for missing or empty compressed state
documents was never addressed in #2895 and is redundant with parseNext()
diagnostics. Downgrade to INFO so routine categorizer state restore
misses no longer trip the serverless ERROR log-rate promotion gate.

Relates #2875

(cherry picked from commit bfaa5cd)

Co-authored-by: Valeriy Khakhutskyy <1292899+valeriy42@users.noreply.github.com>
github-actions Bot added a commit that referenced this pull request Jul 24, 2026
…3082) (#3092)

The LOG_ERROR at readHeader() for missing or empty compressed state
documents was never addressed in #2895 and is redundant with parseNext()
diagnostics. Downgrade to INFO so routine categorizer state restore
misses no longer trip the serverless ERROR log-rate promotion gate.

Relates #2875

(cherry picked from commit bfaa5cd)

Co-authored-by: Valeriy Khakhutskyy <1292899+valeriy42@users.noreply.github.com>
edsavage added a commit that referenced this pull request Aug 13, 2026
…e token ID (#3143)

An inconsistent or truncated categorizer state document can leave a
restored category referencing a token ID at or beyond the end of the
restored token ID lookup. That ID was later used to index the token ID
lookup unchecked (for example when building a reverse search), which is
an out-of-bounds access that can crash the autodetect process with a
SIGSEGV inside libc rather than failing the restore.

Validate, at the end of CTokenListDataCategorizerBase::acceptRestoreTraverser,
that every token ID referenced by a restored category exists in the
restored token ID lookup, and fail the restore gracefully if not. This is
consistent with the graceful invalid-state handling added in #2895/#2898.

Relates to #2875

Co-authored-by: Cursor <cursoragent@cursor.com>
elastic-vault-github-plugin-prod Bot added a commit that referenced this pull request Aug 13, 2026
…e token ID (#3143) (#3152)

An inconsistent or truncated categorizer state document can leave a
restored category referencing a token ID at or beyond the end of the
restored token ID lookup. That ID was later used to index the token ID
lookup unchecked (for example when building a reverse search), which is
an out-of-bounds access that can crash the autodetect process with a
SIGSEGV inside libc rather than failing the restore.

Validate, at the end of CTokenListDataCategorizerBase::acceptRestoreTraverser,
that every token ID referenced by a restored category exists in the
restored token ID lookup, and fail the restore gracefully if not. This is
consistent with the graceful invalid-state handling added in #2895/#2898.

Relates to #2875


(cherry picked from commit 0f41e80)

Co-authored-by: Ed Savage <ed.savage@elastic.co>
Co-authored-by: Cursor <cursoragent@cursor.com>
elastic-vault-github-plugin-prod Bot added a commit that referenced this pull request Aug 13, 2026
…e token ID (#3143) (#3151)

An inconsistent or truncated categorizer state document can leave a
restored category referencing a token ID at or beyond the end of the
restored token ID lookup. That ID was later used to index the token ID
lookup unchecked (for example when building a reverse search), which is
an out-of-bounds access that can crash the autodetect process with a
SIGSEGV inside libc rather than failing the restore.

Validate, at the end of CTokenListDataCategorizerBase::acceptRestoreTraverser,
that every token ID referenced by a restored category exists in the
restored token ID lookup, and fail the restore gracefully if not. This is
consistent with the graceful invalid-state handling added in #2895/#2898.

Relates to #2875


(cherry picked from commit 0f41e80)

Co-authored-by: Ed Savage <ed.savage@elastic.co>
Co-authored-by: Cursor <cursoragent@cursor.com>
elastic-vault-github-plugin-prod Bot added a commit that referenced this pull request Aug 13, 2026
…of-range token ID (#3143) (#3150)

* [ML] Fail gracefully when restoring a categorizer with an out-of-range token ID (#3143)

An inconsistent or truncated categorizer state document can leave a
restored category referencing a token ID at or beyond the end of the
restored token ID lookup. That ID was later used to index the token ID
lookup unchecked (for example when building a reverse search), which is
an out-of-bounds access that can crash the autodetect process with a
SIGSEGV inside libc rather than failing the restore.

Validate, at the end of CTokenListDataCategorizerBase::acceptRestoreTraverser,
that every token ID referenced by a restored category exists in the
restored token ID lookup, and fail the restore gracefully if not. This is
consistent with the graceful invalid-state handling added in #2895/#2898.

Relates to #2875

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 0f41e80)

* [ML] Add missing CJsonStateRestoreTraverser include on 8.19 backport

The cherry-picked unit tests use JSON restore; 8.19's test file only
included RapidXml headers, so all platform builds failed to compile.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Ed Savage <ed.savage@elastic.co>
Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants